diff --git a/app/GlobalKafkaManager.scala b/app/GlobalKafkaManager.scala deleted file mode 100644 index c094cfdca..000000000 --- a/app/GlobalKafkaManager.scala +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright 2015 Yahoo Inc. Licensed under the Apache License, Version 2.0 - * See accompanying LICENSE file. - */ - -import controllers.KafkaManagerContext -import kafka.manager.KafkaManager -import play.api._ - -/** - * @author hiral - */ -object GlobalKafkaManager extends GlobalSettings { - - private[this] var kafkaManager: KafkaManager = null - - override def beforeStart(app: Application): Unit = { - Logger.info("Init kafka manager...") - KafkaManagerContext.getKafkaManager - Thread.sleep(5000) - } - - override def onStop(app: Application) { - KafkaManagerContext.shutdown() - Logger.info("Application shutdown...") - } -} - - diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala index bbf1c1a74..c0ca21ace 100644 --- a/app/controllers/Application.scala +++ b/app/controllers/Application.scala @@ -6,19 +6,19 @@ package controllers import features.ApplicationFeatures -import kafka.manager.features.ClusterFeatures +import models.navigation.Menus +import play.api.i18n.{MessagesApi, I18nSupport} import play.api.mvc._ /** * @author hiral */ -object Application extends Controller { +class Application (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] val kafkaManager = KafkaManagerContext.getKafkaManager - - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + private[this] val kafkaManager = kafkaManagerContext.getKafkaManager def index = Action.async { kafkaManager.getClusterList.map { errorOrClusterList => diff --git a/app/controllers/Cluster.scala b/app/controllers/Cluster.scala index fabe2ef8f..893663cb8 100644 --- a/app/controllers/Cluster.scala +++ b/app/controllers/Cluster.scala @@ -10,10 +10,12 @@ import kafka.manager.model.{KafkaVersion, ClusterConfig} import kafka.manager.ApiError import models.FollowLink import models.form._ +import models.navigation.Menus import play.api.data.Form import play.api.data.Forms._ import play.api.data.validation.{Valid, Invalid, Constraint} import play.api.data.validation.Constraints._ +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ import scala.concurrent.Future @@ -23,11 +25,11 @@ import scalaz.{-\/, \/-} /** * @author hiral */ -object Cluster extends Controller { +class Cluster (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] val kafkaManager = KafkaManagerContext.getKafkaManager - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + private[this] val kafkaManager = kafkaManagerContext.getKafkaManager val validateName : Constraint[String] = Constraint("validate name") { name => Try { diff --git a/app/controllers/Consumer.scala b/app/controllers/Consumer.scala index 5753acc33..298d3b3a6 100644 --- a/app/controllers/Consumer.scala +++ b/app/controllers/Consumer.scala @@ -6,16 +6,19 @@ package controllers import features.ApplicationFeatures +import models.navigation.Menus +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ /** * @author cvcal */ -object Consumer extends Controller{ +class Consumer (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { + import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] val kafkaManager = KafkaManagerContext.getKafkaManager - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + private[this] val kafkaManager = kafkaManagerContext.getKafkaManager def consumers(cluster: String) = Action.async { kafkaManager.getConsumerListExtended(cluster).map { errorOrConsumerList => diff --git a/app/controllers/KMWebJarAssets.scala b/app/controllers/KMWebJarAssets.scala new file mode 100644 index 000000000..e4aca26aa --- /dev/null +++ b/app/controllers/KMWebJarAssets.scala @@ -0,0 +1,83 @@ +package controllers + +import play.api.http.{LazyHttpErrorHandler, HttpErrorHandler} +import play.api.mvc.Action +import play.api.mvc.AnyContent +import scala.util.matching.Regex +import play.api.{Configuration, Play} +import org.webjars.WebJarAssetLocator + +import javax.inject.{ Inject, Singleton } + +/** + * A Play framework controller that is able to resolve WebJar paths. + *
org.webjars.play.webJarFilterExpr can be used to declare a regex for the + * files that should be looked for when searching within WebJars. By default + * all files are searched for. + */ +@Singleton +class KMWebJarAssets @Inject() (errorHandler: HttpErrorHandler, configuration: Configuration) extends AssetsBuilder(errorHandler) { + + val WebjarFilterExprDefault = """.*""" + val WebjarFilterExprProp = "org.webjars.play.webJarFilterExpr" + + val webJarFilterExpr = configuration.getString(WebjarFilterExprProp).getOrElse(WebjarFilterExprDefault) + + import play.api.Play.current + lazy val webJarAssetLocator = new WebJarAssetLocator( + WebJarAssetLocator.getFullPathIndex( + new Regex(webJarFilterExpr).pattern, Play.application.classloader)) + + /** + * Controller Method to serve a WebJar asset + * + * @param file the file to serve + * @return the Action that serves the file + */ + def at(file: String): Action[AnyContent] = { + this.at("/" + WebJarAssetLocator.WEBJARS_PATH_PREFIX, file) + } + + /** + * Locate a file in a WebJar + * + * @example Passing in `jquery.min.js` will return `jquery/1.8.2/jquery.min.js` assuming the jquery WebJar version 1.8.2 is on the classpath + * + * @param file the file or partial path to find + * @return the path to the file (sans-the webjars prefix) + * + */ + def locate(file: String): String = { + webJarAssetLocator.getFullPath(file).stripPrefix(WebJarAssetLocator.WEBJARS_PATH_PREFIX + "/") + } + + /** + * Locate a file in a WebJar + * + * @param webjar the WebJar artifactId + * @param file the file or partial path to find + * @return the path to the file (sans-the webjars prefix) + * + */ + def locate(webjar: String, file: String): String = { + webJarAssetLocator.getFullPath(webjar, file).stripPrefix(WebJarAssetLocator.WEBJARS_PATH_PREFIX + "/") + } + + /** + * Get the full path to a file in a WebJar without validating that the file actually exists + * + * @example Calling fullPath("react", "react.js") will return the full path to the file in the WebJar because react.js exists at the root of the WebJar + * + * @param webjar the WebJar artifactId + * @param path the full path to a file in the WebJar + * @return the path to the file (sans-the webjars prefix) + * + */ + def fullPath(webjar: String, path: String): String = { + val version = webJarAssetLocator.getWebJars.get(webjar) + s"$webjar/$version/$path" + } + +} + +object KMWebJarAssets extends KMWebJarAssets(LazyHttpErrorHandler, play.api.Play.current.configuration) diff --git a/app/controllers/KafkaManagerContext.scala b/app/controllers/KafkaManagerContext.scala index 20478b8a8..3ccea6e6c 100644 --- a/app/controllers/KafkaManagerContext.scala +++ b/app/controllers/KafkaManagerContext.scala @@ -6,17 +6,21 @@ package controllers import kafka.manager.KafkaManager +import play.api.Configuration +import play.api.inject.ApplicationLifecycle + +import scala.concurrent.Future /** * @author hiral */ -object KafkaManagerContext { +class KafkaManagerContext (lifecycle: ApplicationLifecycle, configuration: Configuration) { - import play.api.Play.current + private[this] val kafkaManager : KafkaManager = new KafkaManager(configuration.underlying) + + lifecycle.addStopHook { () => + Future.successful(kafkaManager.shutdown()) + } - private[this] val kafkaManager : KafkaManager = new KafkaManager(play.api.Play.configuration.underlying) def getKafkaManager : KafkaManager = kafkaManager - def shutdown() : Unit = { - kafkaManager.shutdown() - } } diff --git a/app/controllers/Logkafka.scala b/app/controllers/Logkafka.scala index 70aada59f..6957199de 100644 --- a/app/controllers/Logkafka.scala +++ b/app/controllers/Logkafka.scala @@ -20,6 +20,7 @@ import play.api.data.Form import play.api.data.Forms._ import play.api.data.validation.{Valid, Invalid, Constraint} import play.api.data.validation.Constraints._ +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ import scala.concurrent.Future @@ -29,11 +30,11 @@ import scalaz.{\/-, -\/} /** * @author hiral */ -object Logkafka extends Controller{ +class Logkafka (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - implicit private[this] val kafkaManager = KafkaManagerContext.getKafkaManager - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + implicit private[this] val kafkaManager = kafkaManagerContext.getKafkaManager val validateLogkafkaId: Constraint[String] = Constraint("validate logkafka id") { id => Try { @@ -144,7 +145,7 @@ object Logkafka extends Controller{ cl.configs.filter(_.value.isDefined).foreach(c => props.setProperty(c.name, c.value.get)) kafkaManager.createLogkafka(clusterName, cl.logkafka_id, cl.log_path, props).map { errorOrSuccess => Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Logkafka", "Create", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Logkafka", "Create", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Logkafkas", clusterName, "Create Logkafka"), errorOrSuccess, "Create Logkafka", @@ -170,7 +171,7 @@ object Logkafka extends Controller{ deleteLogkafka => { kafkaManager.deleteLogkafka(clusterName, deleteLogkafka.logkafka_id, deleteLogkafka.log_path).map { errorOrSuccess => Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndLogkafka("Logkafka View", clusterName, logkafka_id, log_path, "Delete Logkafka"), errorOrSuccess, "Delete Logkafka", @@ -226,7 +227,7 @@ object Logkafka extends Controller{ updateLogkafkaConfig.configs.filter(_.value.isDefined).foreach(c => props.setProperty(c.name, c.value.get)) kafkaManager.updateLogkafkaConfig(clusterName, updateLogkafkaConfig.logkafka_id, updateLogkafkaConfig.log_path, props).map { errorOrSuccess => Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndLogkafka("Logkafka View", clusterName, logkafka_id, log_path, "Update Config"), errorOrSuccess, "Update Config", @@ -246,7 +247,7 @@ object Logkafka extends Controller{ props.put("valid", true.toString); kafkaManager.updateLogkafkaConfig(clusterName, logkafka_id, log_path, props, false).map { errorOrSuccess => Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndLogkafka("Logkafka View", clusterName, logkafka_id, log_path, "Update Config"), errorOrSuccess, "Enable Config", @@ -264,7 +265,7 @@ object Logkafka extends Controller{ props.put("valid", false.toString); kafkaManager.updateLogkafkaConfig(clusterName, logkafka_id, log_path, props, false).map { errorOrSuccess => Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Logkafka", "Logkafka View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndLogkafka("Logkafka View", clusterName, logkafka_id, log_path, "Update Config"), errorOrSuccess, "Disable Config", diff --git a/app/controllers/PreferredReplicaElection.scala b/app/controllers/PreferredReplicaElection.scala index 937a0430e..dc18c7945 100644 --- a/app/controllers/PreferredReplicaElection.scala +++ b/app/controllers/PreferredReplicaElection.scala @@ -14,6 +14,7 @@ import models.form.{UnknownPREO, RunElection, PreferredReplicaElectionOperation} import play.api.data.Form import play.api.data.Forms._ import play.api.data.validation.{Valid, Invalid, Constraint} +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ import scala.concurrent.Future @@ -22,11 +23,11 @@ import scalaz.-\/ /** * @author hiral */ -object PreferredReplicaElection extends Controller{ +class PreferredReplicaElection (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] val kafkaManager = KafkaManagerContext.getKafkaManager - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + private[this] val kafkaManager = kafkaManagerContext.getKafkaManager private[this] implicit val cf: ClusterFeatures = ClusterFeatures.default @@ -63,7 +64,7 @@ object PreferredReplicaElection extends Controller{ } errorOrSuccessFuture.map { errorOrSuccess => Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(c, "Preferred Replica Election", "", navigation.Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Preferred Replica Election", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withViewAndCluster("Run Election", c), errorOrSuccess, "Run Election", @@ -73,7 +74,7 @@ object PreferredReplicaElection extends Controller{ } case UnknownPREO(opString) => Future.successful(Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(c, "Preferred Replica Election", "", Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Preferred Replica Election", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Preferred Replica Election", c, "Unknown Operation"), -\/(ApiError(s"Unknown operation $opString")), "Unknown Preferred Replica Election Operation", diff --git a/app/controllers/ReassignPartitions.scala b/app/controllers/ReassignPartitions.scala index d2dacdaaa..7023131df 100644 --- a/app/controllers/ReassignPartitions.scala +++ b/app/controllers/ReassignPartitions.scala @@ -15,21 +15,20 @@ import models.form._ import play.api.data.Form import play.api.data.Forms._ import play.api.data.validation.{Valid, Invalid, Constraint} +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ -import scala.collection.mutable - import scala.concurrent.Future import scalaz.{\/, \/-, -\/} /** * @author hiral */ -object ReassignPartitions extends Controller{ +class ReassignPartitions (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] implicit val kafkaManager = KafkaManagerContext.getKafkaManager - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + private[this] implicit val kafkaManager = kafkaManagerContext.getKafkaManager val validateOperation : Constraint[String] = Constraint("validate operation value") { case "confirm" => Valid @@ -273,7 +272,7 @@ object ReassignPartitions extends Controller{ Option(FollowLink("Try Again", routes.ReassignPartitions.manualAssignments(c, t).toString()))))) }, implicit clusterFeatures => { Future.successful(Ok(views.html.common.resultsOfCommand( - views.html.navigation.clusterMenu(c, title, "", Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, title, "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Manual Reassignment View", c, "", title), errorOrResult, title, @@ -319,7 +318,7 @@ object ReassignPartitions extends Controller{ kafkaManager.generatePartitionAssignments(c, Set(t), assignment.brokers.filter(_.selected).map(_.id)).map { errorOrSuccess => implicit val clusterFeatures = cc.clusterFeatures Ok(views.html.common.resultsOfCommand( - views.html.navigation.clusterMenu(c, "Reassign Partitions", "", Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Reassign Partitions", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", c, t, "Generate Partition Assignments"), errorOrSuccess, s"Generate Partition Assignments - $t", @@ -347,7 +346,7 @@ object ReassignPartitions extends Controller{ kafkaManager.generatePartitionAssignments(c, assignment.topics.filter(_.selected).map(_.name).toSet, assignment.brokers.filter(_.selected).map(_.id)).map { errorOrSuccess => implicit val clusterFeatures = cc.clusterFeatures Ok(views.html.common.resultsOfCommand( - views.html.navigation.clusterMenu(c, "Reassign Partitions", "", Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Reassign Partitions", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", c, "", "Generate Partition Assignments"), errorOrSuccess, s"Generate Partition Assignments", @@ -378,7 +377,7 @@ object ReassignPartitions extends Controller{ implicit val clusterFeatures = cc.clusterFeatures Ok( views.html.common.resultsOfCommand( - views.html.navigation.clusterMenu(c, "Reassign Partitions", "", navigation.Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Reassign Partitions", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Topics", c, "Reassign Partitions"), errorOrSuccess, s"Run Reassign Partitions", @@ -407,7 +406,7 @@ object ReassignPartitions extends Controller{ implicit val clusterFeatures = cc.clusterFeatures kafkaManager.runReassignPartitions(c, Set(t)).map { errorOrSuccess => Ok(views.html.common.resultsOfCommand( - views.html.navigation.clusterMenu(c, "Reassign Partitions", "", navigation.Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Reassign Partitions", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", c, t, "Run Reassign Partitions"), errorOrSuccess, s"Run Reassign Partitions - $t", @@ -418,7 +417,7 @@ object ReassignPartitions extends Controller{ case UnknownRPO(opString) => implicit val clusterFeatures = cc.clusterFeatures Future.successful(Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(c, "Reassign Partitions", "", navigation.Menus.clusterMenus(c)), + views.html.navigation.clusterMenu(c, "Reassign Partitions", "", menus.clusterMenus(c)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", c, t, "Unknown Reassign Partitions Operation"), -\/(ApiError(s"Unknown operation $opString")), "Unknown Reassign Partitions Operation", diff --git a/app/controllers/Topic.scala b/app/controllers/Topic.scala index 6c50cb86e..a7d106ba8 100644 --- a/app/controllers/Topic.scala +++ b/app/controllers/Topic.scala @@ -20,6 +20,7 @@ import play.api.data.Form import play.api.data.Forms._ import play.api.data.validation.{Valid, Invalid, Constraint} import play.api.data.validation.Constraints._ +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ import scala.concurrent.Future @@ -29,11 +30,11 @@ import scalaz.{\/-, -\/} /** * @author hiral */ -object Topic extends Controller{ +class Topic (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] val kafkaManager = KafkaManagerContext.getKafkaManager - private[this] implicit val af: ApplicationFeatures = ApplicationFeatures.features + private[this] val kafkaManager = kafkaManagerContext.getKafkaManager val validateName : Constraint[String] = Constraint("validate name") { name => Try { @@ -168,7 +169,7 @@ object Topic extends Controller{ case t => implicit val clusterFeatures = ClusterFeatures.default Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Create", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Create", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Topics", clusterName, "Create Topic"), -\/(ApiError(s"Unknown error : ${t.getMessage}")), "Create Topic", @@ -183,7 +184,7 @@ object Topic extends Controller{ kafkaManager.createTopic(clusterName, ct.topic, ct.partitions, ct.replication, props).map { errorOrSuccess => implicit val clusterFeatures = errorOrSuccess.toOption.map(_.clusterFeatures).getOrElse(ClusterFeatures.default) Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Create", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Create", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Topics", clusterName, "Create Topic"), errorOrSuccess, "Create Topic", @@ -210,7 +211,7 @@ object Topic extends Controller{ kafkaManager.deleteTopic(clusterName, deleteTopic.topic).map { errorOrSuccess => implicit val clusterFeatures = errorOrSuccess.toOption.map(_.clusterFeatures).getOrElse(ClusterFeatures.default) Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", clusterName, topic, "Delete Topic"), errorOrSuccess, "Delete Topic", @@ -274,7 +275,7 @@ object Topic extends Controller{ case t => implicit val clusterFeatures = ClusterFeatures.default Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", clusterName, topic, "Add Partitions"), -\/(ApiError(s"Unknown error : ${t.getMessage}")), "Add Partitions", @@ -287,7 +288,7 @@ object Topic extends Controller{ kafkaManager.addTopicPartitions(clusterName, addTopicPartitions.topic, addTopicPartitions.brokers.filter(_.selected).map(_.id), addTopicPartitions.partitions, addTopicPartitions.readVersion).map { errorOrSuccess => implicit val clusterFeatures = errorOrSuccess.toOption.map(_.clusterFeatures).getOrElse(ClusterFeatures.default) Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", clusterName, topic, "Add Partitions"), errorOrSuccess, "Add Partitions", @@ -310,7 +311,7 @@ object Topic extends Controller{ case t => implicit val clusterFeatures = ClusterFeatures.default Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topics", "Add Partitions to Multiple Topics", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topics", "Add Partitions to Multiple Topics", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Topics", clusterName, "Add Partitions to Multiple Topics"), -\/(ApiError(s"Unknown error : ${t.getMessage}")), "Add Partitions to All Topics", @@ -326,7 +327,7 @@ object Topic extends Controller{ kafkaManager.addMultipleTopicsPartitions(clusterName, topics, brokers, addMultipleTopicsPartitions.partitions, readVersions).map { errorOrSuccess => implicit val clusterFeatures = errorOrSuccess.toOption.map(_.clusterFeatures).getOrElse(ClusterFeatures.default) Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topics", "Add Partitions to Multiple Topics", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topics", "Add Partitions to Multiple Topics", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndCluster("Topics", clusterName, "Add Partitions to Multiple Topics"), errorOrSuccess, "Add Partitions to All Topics", @@ -378,7 +379,7 @@ object Topic extends Controller{ case t => implicit val clusterFeatures = ClusterFeatures.default Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", clusterName, topic, "Update Config"), -\/(ApiError(s"Unknown error : ${t.getMessage}")), "Update Config", @@ -393,7 +394,7 @@ object Topic extends Controller{ kafkaManager.updateTopicConfig(clusterName, updateTopicConfig.topic, props, updateTopicConfig.readVersion).map { errorOrSuccess => implicit val clusterFeatures = errorOrSuccess.toOption.map(_.clusterFeatures).getOrElse(ClusterFeatures.default) Ok(views.html.common.resultOfCommand( - views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", Menus.clusterMenus(clusterName)), + views.html.navigation.clusterMenu(clusterName, "Topic", "Topic View", menus.clusterMenus(clusterName)), models.navigation.BreadCrumbs.withNamedViewAndClusterAndTopic("Topic View", clusterName, topic, "Update Config"), errorOrSuccess, "Update Config", diff --git a/app/controllers/api/KafkaStateCheck.scala b/app/controllers/api/KafkaStateCheck.scala index 1f0729476..b916ebb93 100644 --- a/app/controllers/api/KafkaStateCheck.scala +++ b/app/controllers/api/KafkaStateCheck.scala @@ -6,6 +6,9 @@ package controllers.api import controllers.KafkaManagerContext +import features.ApplicationFeatures +import models.navigation.Menus +import play.api.i18n.{I18nSupport, MessagesApi} import play.api.libs.json._ import play.api.mvc._ @@ -13,11 +16,12 @@ import play.api.mvc._ * @author jisookim0513 */ -object KafkaStateCheck extends Controller { +class KafkaStateCheck (val messagesApi: MessagesApi, val kafkaManagerContext: KafkaManagerContext) + (implicit af: ApplicationFeatures, menus: Menus) extends Controller with I18nSupport { import play.api.libs.concurrent.Execution.Implicits.defaultContext - private[this] val kafkaManager = KafkaManagerContext.getKafkaManager + private[this] val kafkaManager = kafkaManagerContext.getKafkaManager def brokers(c: String) = Action.async { implicit request => kafkaManager.getBrokerList(c).map { errorOrBrokerList => diff --git a/app/features/ApplicationFeature.scala b/app/features/ApplicationFeature.scala index a3055d0cf..cfad0acdd 100644 --- a/app/features/ApplicationFeature.scala +++ b/app/features/ApplicationFeature.scala @@ -48,7 +48,6 @@ object ApplicationFeature extends Logging { case class ApplicationFeatures(features: Set[ApplicationFeature]) object ApplicationFeatures extends Logging { - import play.api.Play.current lazy val default : List[String] = List( KMClusterManagerFeature, @@ -56,10 +55,6 @@ object ApplicationFeatures extends Logging { KMPreferredReplicaElectionFeature, KMReassignPartitionsFeature).map(_.getClass.getSimpleName) - lazy val features = { - getApplicationFeatures(play.api.Play.configuration.underlying) - } - def getApplicationFeatures(config: Config) : ApplicationFeatures = { import scala.collection.JavaConverters._ val configFeatures: Option[List[String]] = Try(config.getStringList("application.features").asScala.toList).toOption diff --git a/app/loader/KafkaManagerLoader.scala b/app/loader/KafkaManagerLoader.scala new file mode 100644 index 000000000..6ba5aae14 --- /dev/null +++ b/app/loader/KafkaManagerLoader.scala @@ -0,0 +1,50 @@ +package loader + +import controllers.{WebJarAssets, KafkaManagerContext} +import features.ApplicationFeatures +import models.navigation.Menus +import play.api.ApplicationLoader +import play.api.ApplicationLoader.Context +import play.api.BuiltInComponentsFromContext +import play.api.i18n.I18nComponents +import play.api.routing.Router +import router.Routes + +/** + * Created by hiral on 12/2/15. + */ +class KafkaManagerLoader extends ApplicationLoader { + def load(context: Context) = { + new ApplicationComponents(context).application + } +} + +class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) with I18nComponents { + private[this] implicit val applicationFeatures = ApplicationFeatures.getApplicationFeatures(context.initialConfiguration.underlying) + private[this] implicit val menus = new Menus + private[this] val kafkaManagerContext = new KafkaManagerContext(applicationLifecycle, context.initialConfiguration) + private[this] lazy val applicationC = new controllers.Application(messagesApi, kafkaManagerContext) + private[this] lazy val clusterC = new controllers.Cluster(messagesApi, kafkaManagerContext) + private[this] lazy val topicC = new controllers.Topic(messagesApi, kafkaManagerContext) + private[this] lazy val logKafkaC = new controllers.Logkafka(messagesApi, kafkaManagerContext) + private[this] lazy val consumerC = new controllers.Consumer(messagesApi, kafkaManagerContext) + private[this] lazy val preferredReplicaElectionC= new controllers.PreferredReplicaElection(messagesApi, kafkaManagerContext) + private[this] lazy val reassignPartitionsC = new controllers.ReassignPartitions(messagesApi, kafkaManagerContext) + private[this] lazy val kafkaStateCheckC = new controllers.api.KafkaStateCheck(messagesApi, kafkaManagerContext) + private[this] lazy val assetsC = new controllers.Assets(httpErrorHandler) + private[this] lazy val webJarsAssetsC = new controllers.KMWebJarAssets(httpErrorHandler, context.initialConfiguration) + + override val router: Router = new Routes( + httpErrorHandler, + applicationC, + clusterC, + topicC, + logKafkaC, + consumerC, + preferredReplicaElectionC, + reassignPartitionsC, + kafkaStateCheckC, + assetsC, + webJarsAssetsC + ) +} diff --git a/app/models/navigation/Menus.scala b/app/models/navigation/Menus.scala index b2cb34880..3d4ef2acc 100644 --- a/app/models/navigation/Menus.scala +++ b/app/models/navigation/Menus.scala @@ -11,10 +11,10 @@ import kafka.manager.features.{KMLogKafkaFeature, ClusterFeatures} /** * @author hiral */ -object Menus { +class Menus(implicit applicationFeatures: ApplicationFeatures) { import models.navigation.QuickRoutes._ - private[this] def clusterMenu(cluster: String, applicationFeatures: ApplicationFeatures) : Option[Menu] = { + private[this] def clusterMenu(cluster: String) : Option[Menu] = { val defaultItems = IndexedSeq("Summary".clusterRouteMenuItem(cluster), "List".baseRouteMenuItem) val items = { @@ -27,7 +27,7 @@ object Menus { Option(Menu("Cluster", items, None)) } - private[this] def topicMenu(cluster: String, applicationFeatures: ApplicationFeatures) : Option[Menu] = { + private[this] def topicMenu(cluster: String) : Option[Menu] = { val defaultItems = IndexedSeq("List".clusterRouteMenuItem(cluster)) val items = { @@ -40,24 +40,23 @@ object Menus { Option(Menu("Topic", items, None)) } - private[this] def brokersMenu(cluster: String, applicationFeatures: ApplicationFeatures) : Option[Menu] = { + private[this] def brokersMenu(cluster: String) : Option[Menu] = { Option("Brokers".clusterMenu(cluster)) } - private[this] def preferredReplicaElectionMenu(cluster: String, applicationFeatures: ApplicationFeatures) : Option[Menu] = { + private[this] def preferredReplicaElectionMenu(cluster: String) : Option[Menu] = { Option("Preferred Replica Election".clusterMenu(cluster)) } - private[this] def reassignPartitionsMenu(cluster: String, applicationFeatures: ApplicationFeatures) : Option[Menu] = { + private[this] def reassignPartitionsMenu(cluster: String) : Option[Menu] = { Option("Reassign Partitions".clusterMenu(cluster)) } - private[this] def consumersMenu(cluster: String, applicationFeatures: ApplicationFeatures) : Option[Menu] = { + private[this] def consumersMenu(cluster: String) : Option[Menu] = { Option("Consumers".clusterMenu(cluster)) } private[this] def logKafkaMenu(cluster: String, - applicationFeatures: ApplicationFeatures, clusterFeatures: ClusterFeatures) : Option[Menu] = { if (clusterFeatures.features(KMLogKafkaFeature)) { Option(Menu("Logkafka", IndexedSeq( @@ -68,23 +67,22 @@ object Menus { } def clusterMenus(cluster: String) - (implicit applicationFeatures: ApplicationFeatures, - clusterFeatures: ClusterFeatures) : IndexedSeq[Menu] = { + (implicit clusterFeatures: ClusterFeatures) : IndexedSeq[Menu] = { IndexedSeq( - clusterMenu(cluster, applicationFeatures), - brokersMenu(cluster, applicationFeatures), - topicMenu(cluster, applicationFeatures), - preferredReplicaElectionMenu(cluster, applicationFeatures), - reassignPartitionsMenu(cluster, applicationFeatures), - consumersMenu(cluster, applicationFeatures), - logKafkaMenu(cluster, applicationFeatures, clusterFeatures) + clusterMenu(cluster), + brokersMenu(cluster), + topicMenu(cluster), + preferredReplicaElectionMenu(cluster), + reassignPartitionsMenu(cluster), + consumersMenu(cluster), + logKafkaMenu(cluster, clusterFeatures) ).flatten } val indexMenu = { val defaultItems = IndexedSeq("List".baseRouteMenuItem) val items = { - if(ApplicationFeatures.features.features(KMClusterManagerFeature)) + if(applicationFeatures.features(KMClusterManagerFeature)) defaultItems.+:("Add Cluster".baseRouteMenuItem) else defaultItems diff --git a/app/views/broker/brokerList.scala.html b/app/views/broker/brokerList.scala.html index 737151e08..582a03d0c 100644 --- a/app/views/broker/brokerList.scala.html +++ b/app/views/broker/brokerList.scala.html @@ -5,11 +5,10 @@ @import kafka.manager.model.ActorModel.BrokerIdentity @import scalaz.{\/} @(cluster:String, errorOrBrokers: kafka.manager.ApiError \/ kafka.manager.BrokerListExtended -)(implicit af: features.ApplicationFeatures) +)(implicit af: features.ApplicationFeatures, messages: play.api.i18n.Messages, menus: models.navigation.Menus) @theMenu = { - @views.html.navigation.clusterMenu(cluster,"Brokers","",models.navigation.Menus.clusterMenus(cluster)( - af, + @views.html.navigation.clusterMenu(cluster,"Brokers","",menus.clusterMenus(cluster)( errorOrBrokers.toOption.map(_.clusterContext.clusterFeatures).getOrElse(kafka.manager.features.ClusterFeatures.default))) } diff --git a/app/views/broker/brokerListContent.scala.html b/app/views/broker/brokerListContent.scala.html index adfd9a373..4ad5abdcf 100644 --- a/app/views/broker/brokerListContent.scala.html +++ b/app/views/broker/brokerListContent.scala.html @@ -3,7 +3,7 @@ * See accompanying LICENSE file. *@ @import kafka.manager.model.ActorModel.BrokerIdentity -@(cluster:String, brokerListExtended: kafka.manager.BrokerListExtended) +@(cluster:String, brokerListExtended: kafka.manager.BrokerListExtended)(implicit messages: play.api.i18n.Messages)
Rate | diff --git a/app/views/common/resultOfCommand.scala.html b/app/views/common/resultOfCommand.scala.html index 032331df6..38ff898aa 100644 --- a/app/views/common/resultOfCommand.scala.html +++ b/app/views/common/resultOfCommand.scala.html @@ -8,7 +8,7 @@ errorOrSuccess: kafka.manager.ApiError \/ Any, actionTitle: String, successLink: models.FollowLink, - errorLink: models.FollowLink) + errorLink: models.FollowLink)(implicit messages: play.api.i18n.Messages) @link(followLink: FollowLink) = {
---|