Browse files

Merge branch 'release/0.0.4'

  • Loading branch information...
2 parents 115f805 + a497538 commit 6e1764fa805a89cac4540e6449db632cff631bff @codahale codahale committed May 10, 2011
Showing with 521 additions and 437 deletions.
  1. +6 −7 README.md
  2. +2 −2 project/build.properties
  3. +8 −12 project/build/DropwizardProject.scala
  4. +130 −0 src/main/scala/com/yammer/dropwizard/Environment.scala
  5. +22 −0 src/main/scala/com/yammer/dropwizard/JerseyConfig.scala
  6. +5 −24 src/main/scala/com/yammer/dropwizard/Service.scala
  7. +4 −14 src/main/scala/com/yammer/dropwizard/cli/Command.scala
  8. +7 −5 src/main/scala/com/yammer/dropwizard/cli/ConfiguredCommand.scala
  9. +9 −5 src/main/scala/com/yammer/dropwizard/cli/ManagedCommand.scala
  10. +14 −32 src/main/scala/com/yammer/dropwizard/cli/ServerCommand.scala
  11. +57 −0 src/main/scala/com/yammer/dropwizard/config/ConfigurationFactory.scala
  12. +4 −12 ...yammer/dropwizard/{modules/RequestLogHandlerModule.scala → config/RequestLogHandlerFactory.scala}
  13. +104 −0 src/main/scala/com/yammer/dropwizard/config/ServerFactory.scala
  14. +0 −24 src/main/scala/com/yammer/dropwizard/jersey/ScanningGuiceContainer.scala
  15. +7 −16 src/main/scala/com/yammer/dropwizard/lifecycle/JettyManager.scala
  16. +0 −49 src/main/scala/com/yammer/dropwizard/modules/ConfigurationModule.scala
  17. +0 −25 src/main/scala/com/yammer/dropwizard/modules/GuiceModule.scala
  18. +0 −11 src/main/scala/com/yammer/dropwizard/modules/GuiceMultibindingModule.scala
  19. +0 −31 src/main/scala/com/yammer/dropwizard/modules/GuiceServletModule.scala
  20. +0 −11 src/main/scala/com/yammer/dropwizard/modules/JerseyServletModule.scala
  21. +0 −9 src/main/scala/com/yammer/dropwizard/modules/ProviderModule.scala
  22. +0 −89 src/main/scala/com/yammer/dropwizard/modules/ServerModule.scala
  23. +1 −1 src/main/scala/com/yammer/dropwizard/{jersey → providers}/LoggingExceptionMapper.scala
  24. +0 −10 src/main/scala/com/yammer/dropwizard/service/Jersey.scala
  25. +78 −0 src/main/scala/com/yammer/dropwizard/util/QuietErrorHandler.scala
  26. +25 −5 src/test/resources/example.conf
  27. +11 −7 src/test/scala/com/yammer/dropwizard/examples/Example.scala
  28. +11 −6 src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala
  29. +5 −4 src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala
  30. +7 −0 src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala
  31. +0 −16 src/test/scala/com/yammer/dropwizard/examples/SayingModule.scala
  32. +3 −8 src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala
  33. +1 −2 src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala
View
13 README.md
@@ -5,13 +5,12 @@ Dropwizard
It's a little bit of opinionated glue code which bangs together a set of libraries which have historically not sucked:
-- [Jetty](http://www.eclipse.org/jetty/) for HTTP servin'.
-- [Jersey](http://jersey.java.net/) for REST modelin'.
-- [Guice](http://code.google.com/p/google-guice/) for dependency injectin'.
-- [Fig](https://github.com/codahale/fig) for JSON configurin'.
-- [Jerkson](https://github.com/codahale/jerkson)/[Jackson](http://jackson.codehaus.org) for JSON parsin' and generatin'.
-- [Logula](https://github.com/codahale/logula)/[Log4j](http://logging.apache.org/log4j/1.2/) for loggin'.
-- [Metrics](https://github.com/codahale/metrics) for figurin' out what your service is doing in production.
+* [Jetty](http://www.eclipse.org/jetty/) for HTTP servin'.
+* [Jersey](http://jersey.java.net/) for REST modelin'.
+* [Fig](https://github.com/codahale/fig) for JSON configurin'.
+* [Jerkson](https://github.com/codahale/jerkson)/[Jackson](http://jackson.codehaus.org) for JSON parsin' and generatin'.
+* [Logula](https://github.com/codahale/logula)/[Log4j](http://logging.apache.org/log4j/1.2/) for loggin'.
+* [Metrics](https://github.com/codahale/metrics) for figurin' out what your service is doing in production.
[Yammer](https://www.yammer.com)'s high-performance, low-latency, Scala services all use Dropwizard. In fact, Dropwizard
is really just a simple extraction of [Yammer](https://www.yammer.com)'s glue code.
View
4 project/build.properties
@@ -2,7 +2,7 @@
#Mon Jan 17 19:25:38 PST 2011
project.organization=com.yammer
project.name=dropwizard
-sbt.version=0.7.5.RC0
-project.version=0.0.3
+sbt.version=0.7.6.RC0
+project.version=0.0.4
build.scala.versions=2.8.1
project.initialize=false
View
20 project/build/DropwizardProject.scala
@@ -32,27 +32,23 @@ class DropwizardProject(info: ProjectInfo) extends DefaultProject(info)
val mockito = "org.mockito" % "mockito-all" % "1.8.4" % "test"
/**
- * Guice Dependencies
- */
- val guice = "com.google.inject" % "guice" % "3.0"
- val guiceServlet = "com.google.inject.extensions" % "guice-servlet" % "3.0"
- val guiceMultibindings = "com.google.inject.extensions" % "guice-multibindings" % "3.0"
-
- /**
* Jersey Dependencies
*/
val jerseyScala = "com.codahale" %% "jersey-scala" % "0.1.3"
- // TODO: 3/29/11 <coda> -- Change back to regular packaging once
- // http://java.net/jira/browse/JERSEY-697 is resolved.
- val jerseyGuice = "com.sun.jersey.contribs" % "jersey-guice-nogrizzly" % "1.6"
/**
* Misc Dependencies
*/
val fig = "com.codahale" %% "fig" % "1.1.1"
- val jerkson = "com.codahale" %% "jerkson" % "0.1.7"
- val metrics = "com.yammer" %% "metrics" % "2.0.0-BETA11"
+ val jerkson = "com.codahale" %% "jerkson" % "0.1.8"
+ val metricsVersion = "2.0.0-BETA12"
+ val metricsCore = "com.yammer.metrics" %% "metrics-core" % metricsVersion
+ val metricsServlet = "com.yammer.metrics" %% "metrics-servlet" % metricsVersion
+ val metricsJetty = "com.yammer.metrics" %% "metrics-jetty" % metricsVersion
+ val metricsLog4j = "com.yammer.metrics" %% "metrics-log4j" % metricsVersion
val commonsCli = "commons-cli" % "commons-cli" % "1.2"
+ val jacksonCore = "org.codehaus.jackson" % "jackson-core-asl" % "1.7.6"
+ val jacksonMapper = "org.codehaus.jackson" % "jackson-mapper-asl" % "1.7.6"
/**
* Logging Dependencies
View
130 src/main/scala/com/yammer/dropwizard/Environment.scala
@@ -0,0 +1,130 @@
+package com.yammer.dropwizard
+
+import collection.JavaConversions._
+import lifecycle.Managed
+import com.sun.jersey.api.core.ResourceConfig._
+import com.codahale.logula.Logging
+import com.yammer.metrics.core.HealthCheck
+import javax.servlet.{Servlet, Filter}
+import com.sun.jersey.core.reflection.MethodList
+import javax.ws.rs.{Path, HttpMethod}
+import org.eclipse.jetty.servlet.{ServletHolder, FilterHolder}
+
+class Environment extends Logging {
+ private[dropwizard] var resources = Set.empty[Object]
+ private[dropwizard] var healthChecks = Set.empty[HealthCheck]
+ private[dropwizard] var providers = Set.empty[Object]
+ private[dropwizard] var managedObjects = IndexedSeq.empty[Managed]
+ private[dropwizard] var filters = Map.empty[String, FilterHolder]
+ private[dropwizard] var servlets = Map.empty[String, ServletHolder]
+
+ def addResource(resource: Object) {
+ if (!isRootResourceClass(resource.getClass)) {
+ throw new IllegalArgumentException(resource.getClass.getCanonicalName +
+ " is not a @Path-annotated resource class")
+ }
+
+ if (annotatedMethods(resource).isEmpty) {
+ throw new IllegalArgumentException(resource.getClass.getCanonicalName +
+ " has no @GET/@POST/etc-annotated methods")
+ }
+
+ resources += resource
+ }
+
+ def addProvider(provider: Object) {
+ if (!isProviderClass(provider.getClass)) {
+ throw new IllegalArgumentException(provider.getClass.getCanonicalName +
+ " is not a @Provider-annotated provider class")
+ }
+ providers += provider
+ }
+
+ def addHealthCheck(healthCheck: HealthCheck) {
+ healthChecks += healthCheck
+ }
+
+ def manage(managedObject: Managed) {
+ managedObjects ++= IndexedSeq(managedObject)
+ }
+
+ def addFilter[T <: Filter](filter: T,
+ pathSpec: String,
+ params: Map[String, String] = Map.empty) {
+ val holder = new FilterHolder(filter)
+ holder.setInitParameters(params)
+ filters += pathSpec -> holder
+ }
+
+ def addFilterClass[T <: Filter](klass: Class[T],
+ pathSpec: String,
+ params: Map[String, String] = Map.empty) {
+ val holder = new FilterHolder(klass)
+ holder.setInitParameters(params)
+ filters += pathSpec -> holder
+ }
+
+ def addServlet[T <: Servlet](servlet: T,
+ pathSpec: String,
+ params: Map[String, String] = Map.empty,
+ initOrder: Int = 0) {
+ val holder = new ServletHolder(servlet)
+ holder.setInitParameters(params)
+ holder.setInitOrder(initOrder)
+ servlets += pathSpec -> holder
+ }
+
+ def addServletClass[T <: Servlet](klass: Class[T],
+ pathSpec: String,
+ params: Map[String, String] = Map.empty,
+ initOrder: Int = 0) {
+ val holder = new ServletHolder(klass)
+ holder.setInitParameters(params)
+ holder.setInitOrder(initOrder)
+ servlets += pathSpec -> holder
+ }
+
+ private[dropwizard] def validate() {
+ def logResources() {
+ def httpMethods(resource: Object) = annotatedMethods(resource).map {
+ _.getMetaMethodAnnotations(classOf[HttpMethod]).map { _.value() }
+ }.flatten.toIndexedSeq.sorted
+
+ def paths(resource: Object) =
+ resource.getClass.getAnnotation(classOf[Path]).value() :: Nil
+
+ val out = new StringBuilder("\n\n")
+ for (resource <- resources;
+ path <- paths(resource);
+ method <- httpMethods(resource)) {
+ out.append(" %s %s (%s)\n".format(method, path, resource.getClass.getCanonicalName))
+ }
+ log.info(out.toString())
+ }
+
+ log.debug("resources = %s", resources.mkString("{", ", ", "}"))
+ log.debug("providers = %s", providers.mkString("{", ", ", "}"))
+ log.debug("health checks = %s", healthChecks.mkString("{", ", ", "}"))
+ log.debug("managed objects = %s", managedObjects.mkString("{", ", ", "}"))
+
+ logResources()
+
+ if (healthChecks.isEmpty) {
+ log.warn("""
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! THIS SERVICE HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW IF IT !
+! DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE LETTING !
+! YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH DEPENDENCY OF !
+! YOUR SERVICE WHICH FULLY (BUT LIGHTLY) TESTS YOUR SERVICE'S ABILITY TO !
+! USE THAT SERVICE. THINK OF IT AS A CONTINUOUS INTEGRATION TEST. !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+""")
+ }
+ }
+
+ private def annotatedMethods(resource: Object) =
+ new MethodList(resource.getClass, true).hasMetaAnnotation(classOf[HttpMethod])
+}
View
22 src/main/scala/com/yammer/dropwizard/JerseyConfig.scala
@@ -0,0 +1,22 @@
+package com.yammer.dropwizard
+
+import com.sun.jersey.api.core.DefaultResourceConfig
+import com.codahale.logula.Logging
+import providers.LoggingExceptionMapper
+import com.codahale.jersey.inject.ScalaCollectionsQueryParamInjectableProvider
+import com.codahale.jersey.providers.{JValueProvider, JsonCaseClassProvider}
+
+class JerseyConfig(env: Environment) extends DefaultResourceConfig with Logging {
+ (
+ Set(
+ new LoggingExceptionMapper,
+ new JsonCaseClassProvider,
+ new ScalaCollectionsQueryParamInjectableProvider,
+ new JValueProvider
+ ) ++ env.resources ++ env.providers
+ ).foreach(getSingletons.add)
+
+ override def validate() {
+ env.validate()
+ }
+}
View
29 src/main/scala/com/yammer/dropwizard/Service.scala
@@ -1,48 +1,29 @@
package com.yammer.dropwizard
-import collection.{immutable, mutable}
-import lifecycle.Managed
-import modules.{GuiceMultibindingModule, ServerModule, RequestLogHandlerModule}
+import collection.immutable
import util.JarAware
import com.codahale.logula.Logging
-import com.google.inject.Module
import com.yammer.dropwizard.cli.{ServerCommand, Command}
-import com.yammer.metrics.guice.InstrumentationModule
-import com.yammer.metrics.core.{DeadlockHealthCheck, HealthCheck}
+import com.codahale.fig.Configuration
trait Service extends Logging with JarAware {
- private val modules = new mutable.ArrayBuffer[Module]() ++ Seq(
- new RequestLogHandlerModule,
- new ServerModule,
- new InstrumentationModule
- )
- protected def require(modules: Module*) { this.modules ++= modules }
-
private var commands = new immutable.TreeMap[String, Command]
protected def provide(commands: Command*) { commands.foreach { c => this.commands += c.name -> c } }
provide(new ServerCommand(this))
-
- protected def healthCheck[A <: HealthCheck](implicit mf: Manifest[A]) {
- modules += new GuiceMultibindingModule(classOf[HealthCheck], mf.erasure.asInstanceOf[Class[HealthCheck]])
- }
- healthCheck[DeadlockHealthCheck]
-
- protected def manage[A <: Managed](implicit mf: Manifest[A]) {
- modules += new GuiceMultibindingModule(classOf[Managed], mf.erasure.asInstanceOf[Class[Managed]])
- }
def name: String
def banner: Option[String] = None
+ def configure(implicit config: Configuration, environment: Environment)
+
private def printUsage(error: Option[String] = None) {
for (msg <- error) {
System.err.printf("%s\n\n", msg)
}
printf("%s <command> [arg1 arg2]\n\n", jarSyntax)
-
println("Commands")
println("========\n")
for (cmd <- commands.values) {
@@ -57,7 +38,7 @@ trait Service extends Logging with JarAware {
case command :: args => {
commands.get(command) match {
case Some(cmd) => {
- cmd.execute(jarSyntax, modules.toSeq, args)
+ cmd.execute(this, jarSyntax, args)
}
case None => printUsage(Some("Unrecognized command: " + command))
}
View
18 src/main/scala/com/yammer/dropwizard/cli/Command.scala
@@ -1,14 +1,9 @@
package com.yammer.dropwizard.cli
-import collection.mutable
-import com.google.inject._
import org.apache.commons.cli.{ParseException, GnuParser, Options, HelpFormatter, Option => ApacheOption, OptionGroup}
+import com.yammer.dropwizard.Service
trait Command {
- private val modules = new mutable.ArrayBuffer[Module]
-
- protected def require(modules: Module*) {this.modules ++= modules}
-
def name: String
def description: Option[String] = None
@@ -32,10 +27,8 @@ trait Command {
opts
}
- def execute(jarSyntax: String, modules: Seq[Module], args: Seq[String]) {
+ def execute(service: Service, jarSyntax: String, args: Seq[String]) {
try {
- this.modules ++= modules
-
if (args == Seq("-h") || args == Seq("--help")) {
printUsage(jarSyntax, None)
} else {
@@ -46,28 +39,25 @@ trait Command {
Option(o.getValues).getOrElse(Array.empty[String]).toList
}.toMap
- run(opts, cmdLine.getArgs.toList).foreach { e =>
+ run(service, opts, cmdLine.getArgs.toList).foreach { e =>
printUsage(jarSyntax, Some(e))
}
}
} catch {
case e: ParseException => {
printUsage(jarSyntax, Some(e.getMessage))
}
- case e: CreationException => System.err.println(e.getMessage)
case e => {
e.printStackTrace()
}
}
}
- def run(opts: Map[String, List[String]], args: List[String]): Option[String]
+ def run(service: Service, opts: Map[String, List[String]], args: List[String]): Option[String]
protected def commandSyntax(jarSyntax: String) =
"%s %s [options] [arguments]".format(jarSyntax, name)
- protected lazy val injector = Guice.createInjector(Stage.PRODUCTION, modules: _*)
-
def printUsage(jarSyntax: String, error: Option[String] = None) {
for (msg <- error) {
System.err.printf("%s\n\n", msg)
View
12 src/main/scala/com/yammer/dropwizard/cli/ConfiguredCommand.scala
@@ -2,20 +2,22 @@ package com.yammer.dropwizard.cli
import java.io.File
import com.codahale.jerkson.ParsingException
-import com.yammer.dropwizard.modules.ConfigurationModule
import com.codahale.logula.Logging
+import com.yammer.dropwizard.config.ConfigurationFactory
+import com.codahale.fig.Configuration
+import com.yammer.dropwizard.Service
trait ConfiguredCommand extends Command with Logging {
override protected def commandSyntax(jarSyntax: String) =
"%s %s [options] <config file> [argumemts]".format(jarSyntax, name)
- final def run(opts: Map[String, List[String]], args: List[String]) = args match {
+ final def run(service: Service, opts: Map[String, List[String]], args: List[String]) = args match {
case filename :: others => {
val f = new File(filename)
if (f.exists && f.isFile) {
try {
- require(new ConfigurationModule(filename))
- runWithConfigFile(opts, others)
+ val config = ConfigurationFactory.buildConfiguration(filename)
+ run(service, config, opts, others)
} catch {
case e: ParsingException => Some("Bad configuration file: " + e.getMessage)
case e => Some("Error: " + e.getMessage)
@@ -27,5 +29,5 @@ trait ConfiguredCommand extends Command with Logging {
case Nil => Some("no configuration file specified")
}
- def runWithConfigFile(opts: Map[String, List[String]], args: List[String]): Option[String]
+ def run(service: Service, config: Configuration, opts: Map[String, List[String]], args: List[String]): Option[String]
}
View
14 src/main/scala/com/yammer/dropwizard/cli/ManagedCommand.scala
@@ -1,19 +1,23 @@
package com.yammer.dropwizard.cli
import org.eclipse.jetty.util.component.AggregateLifeCycle
+import com.codahale.fig.Configuration
+import com.yammer.dropwizard.{Environment, Service}
import com.yammer.dropwizard.lifecycle.JettyManager
-trait ManagedCommand extends Command {
- final def run(opts: Map[String, List[String]], args: List[String]) = {
+trait ManagedCommand extends ConfiguredCommand {
+ final def run(service: Service, config: Configuration, opts: Map[String, List[String]], args: List[String]): Option[String] = {
val aggregate = new AggregateLifeCycle
- JettyManager.collect(injector).foreach(aggregate.addBean)
+ val env = new Environment
+ service.configure(config, env)
+ env.managedObjects.map {new JettyManager(_)}.foreach(aggregate.addBean)
aggregate.start()
try {
- runWithManagement(opts, args)
+ run(opts, args)
} finally {
aggregate.stop()
}
}
- def runWithManagement(opts: Map[String, List[String]], args: List[String]): Option[String]
+ def run(opts: Map[String, List[String]], args: List[String]): Option[String]
}
View
46 src/main/scala/com/yammer/dropwizard/cli/ServerCommand.scala
@@ -1,12 +1,12 @@
package com.yammer.dropwizard.cli
-import collection.JavaConversions._
-import org.eclipse.jetty.server.Server
-import com.yammer.dropwizard.Service
import com.yammer.metrics.HealthChecks
-import com.yammer.metrics.core.HealthCheck
-import com.google.inject.{ConfigurationException, Key, TypeLiteral}
+import com.codahale.fig.Configuration
+import com.yammer.dropwizard.config.ServerFactory
+import com.sun.jersey.spi.container.servlet.ServletContainer
+import com.yammer.metrics.core.DeadlockHealthCheck
import com.yammer.dropwizard.lifecycle.JettyManager
+import com.yammer.dropwizard.{JerseyConfig, Environment, Service}
class ServerCommand(service: Service) extends ConfiguredCommand {
def name = "server"
@@ -17,40 +17,22 @@ class ServerCommand(service: Service) extends ConfiguredCommand {
override def description = Some("Starts an HTTP server running the service")
- private def complainAboutHealthChecks() {
- log.warn("""
-
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! THIS SERVICE HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW IF IT !
-! DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE LETTING !
-! YOUR USERS DOWN. ADD HEALTHCHECKS OR FEAR THE WRATH OF THE DROP WIZARD. !
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-""")
- }
-
- final def runWithConfigFile(opts: Map[String, List[String]],
- args: List[String]) = {
- try {
- val healthchecks = injector.getInstance(Key.get(new TypeLiteral[java.util.Set[HealthCheck]]() {}))
- healthchecks.foreach(HealthChecks.register)
+ final def run(service: Service, config: Configuration, opts: Map[String, List[String]], args: List[String]) = {
+ val env = new Environment
+ service.configure(config, env)
+ env.healthChecks.foreach(HealthChecks.register)
+ HealthChecks.register(new DeadlockHealthCheck)
+ env.addServlet(new ServletContainer(new JerseyConfig(env)), "/*")
- if (healthchecks.size == 1) {
- complainAboutHealthChecks()
- }
- } catch {
- case e: ConfigurationException => complainAboutHealthChecks()
- }
+ val server = ServerFactory.provideServer(config, env.servlets, env.filters)
+ env.managedObjects.map { new JettyManager(_) }.foreach(server.addBean)
log.info("Starting %s", service.name)
-
service.banner.foreach {s => log.info("\n%s\n", s)}
- val server = injector.getInstance(classOf[Server])
- JettyManager.collect(injector).foreach(server.addBean)
server.start()
server.join()
+
None
}
}
View
57 src/main/scala/com/yammer/dropwizard/config/ConfigurationFactory.scala
@@ -0,0 +1,57 @@
+package com.yammer.dropwizard.config
+
+import com.codahale.fig.Configuration
+import java.util.logging.Logger
+import org.slf4j.bridge.SLF4JBridgeHandler
+import com.codahale.logula.Logging
+import org.apache.log4j.{LogManager, Level}
+import org.apache.log4j.varia.NullAppender
+import com.yammer.metrics.log4j.InstrumentedAppender
+
+object ConfigurationFactory {
+ def buildConfiguration(filename: String) = {
+ val config = new Configuration(filename)
+ configureLogging(config)
+ config
+ }
+
+ private def configureLogging(config: Configuration) {
+ val rootLogger = Logger.getLogger("")
+ rootLogger.getHandlers.foreach(rootLogger.removeHandler)
+ rootLogger.addHandler(new SLF4JBridgeHandler)
+ Logging.configure { log =>
+ log.registerWithJMX = true
+
+ log.level = Level.toLevel(config("logging.level").or("info"), Level.INFO)
+
+ for ((name, level) <- config("logging.loggers").asMap[String]) {
+ log.loggers(name.toString) = Level.toLevel(level, Level.INFO)
+ }
+
+ log.console.enabled = config("logging.console.enabled").or(true)
+
+ config("logging.console.threshold").asOption[String].foreach {l =>
+ log.console.threshold = Level.toLevel(l, Level.ALL)
+ }
+
+ if (config("logging.file.enabled").or(false)) {
+ log.file.enabled = true
+ log.file.filename = config("logging.file.filename").asRequired[String]
+ log.file.maxSize = config("logging.file.max_log_size_kilobytes").or(10240)
+ log.file.retainedFiles = config("logging.file.retain_files").or(1)
+ config("logging.file.threshold").asOption[String].foreach {l =>
+ log.file.threshold = Level.toLevel(l, Level.ALL)
+ }
+ }
+
+ if (config("logging.syslog.enabled").or(false)) {
+ log.syslog.enabled = true
+ log.syslog.host = config("logging.syslog.host").asRequired[String]
+ log.syslog.facility = config("logging.syslog.facility").asRequired[String]
+ }
+ }
+
+ // add in an instrumented null appender to get full logging stats
+ LogManager.getRootLogger.addAppender(new InstrumentedAppender(new NullAppender))
+ }
+}
View
16 ...ard/modules/RequestLogHandlerModule.scala → ...ard/config/RequestLogHandlerFactory.scala
@@ -1,19 +1,11 @@
-package com.yammer.dropwizard.modules
+package com.yammer.dropwizard.config
-import org.eclipse.jetty.server.handler.RequestLogHandler
import com.codahale.fig.Configuration
-import com.google.inject.{Provides, Singleton}
import org.eclipse.jetty.server.NCSARequestLog
+import org.eclipse.jetty.server.handler.RequestLogHandler
-/**
- * Given a Configuration instance, provides a RequestLogHandler instance.
- *
- * @author coda
- */
-class RequestLogHandlerModule extends ProviderModule {
- @Provides
- @Singleton
- def provideRequestLogHandler(config: Configuration): RequestLogHandler = {
+object RequestLogHandlerFactory {
+ def buildHandler(implicit config: Configuration) = {
val log = new NCSARequestLog
log.setIgnorePaths(config("request_log.ignore_paths").asList[String].toArray)
config("request_log.append").asOption[Boolean].foreach(log.setAppend)
View
104 src/main/scala/com/yammer/dropwizard/config/ServerFactory.scala
@@ -0,0 +1,104 @@
+package com.yammer.dropwizard.config
+
+import com.codahale.fig.Configuration
+import com.yammer.metrics.jetty.InstrumentedHandler
+import org.eclipse.jetty.server.handler.HandlerCollection
+import org.eclipse.jetty.server.bio.SocketConnector
+import org.eclipse.jetty.server.nio.{BlockingChannelConnector, SelectChannelConnector}
+import org.eclipse.jetty.util.thread.QueuedThreadPool
+import com.yammer.metrics.reporting.MetricsServlet
+import org.eclipse.jetty.servlet._
+import javax.servlet.{Filter, Servlet}
+import java.util.EnumSet
+import org.eclipse.jetty.server.{DispatcherType, Server, Connector}
+import com.yammer.dropwizard.util.QuietErrorHandler
+
+object ServerFactory {
+ def provideServer(implicit config: Configuration,
+ servlets: Map[String, ServletHolder],
+ filters: Map[String, FilterHolder]) = {
+ val server = makeServer(mainConnector, internalConnector)
+
+ val handlers = new HandlerCollection
+ handlers.addHandler(new InstrumentedHandler(servletContext))
+ handlers.addHandler(internalServletContext)
+ if (config("request_log.enabled").or(false)) {
+ handlers.addHandler(RequestLogHandlerFactory.buildHandler)
+ }
+ server.setHandler(handlers)
+
+ server
+ }
+
+ private def newConnector(implicit config: Configuration) =
+ config("http.connector").or("blocking_channel") match {
+ case "socket" => new SocketConnector
+ case "select_channel" => {
+ val connector = new SelectChannelConnector
+ connector.setAcceptors(config("http.acceptor_threads").or(2))
+ connector.setMaxIdleTime(config("http.max_idle_time_seconds").or(300))
+ connector.setLowResourcesConnections(config("http.low_resources_connections").or(25000))
+ connector.setLowResourcesMaxIdleTime(config("http.low_resources_max_idle_time_seconds").or(5))
+ connector
+ }
+ case "blocking_channel" => new BlockingChannelConnector
+ }
+
+ private def mainConnector(implicit config: Configuration) = {
+ val port = config("http.port").or(8080)
+ val connector = newConnector(config)
+ config("http.hostname").asOption[String].foreach(connector.setHost)
+ connector.setForwarded(config("http.forwarded").or(false))
+ connector.setPort(port)
+ connector.setName("main")
+ connector
+ }
+
+ private def makeServer(connectors: Connector*)(implicit config: Configuration) = {
+ val server = new Server
+ connectors.foreach(server.addConnector)
+ server.addBean(new QuietErrorHandler)
+ server.setSendServerVersion(false)
+ server.setThreadPool(makeThreadPool)
+ server.setStopAtShutdown(true)
+ server.setGracefulShutdown(config("http.shutdown_milliseconds").or(2000))
+ server
+ }
+
+ private def makeThreadPool(implicit config: Configuration) = {
+ val pool = new QueuedThreadPool
+ config("http.max_threads").asOption[Int].foreach(pool.setMaxThreads)
+ config("http.min_threads").asOption[Int].foreach(pool.setMinThreads)
+ pool
+ }
+
+ private def internalConnector(implicit config: Configuration) = {
+ val connector = new SocketConnector
+ connector.setPort(config("metrics.port").or(8081))
+ connector.setName("internal")
+ connector
+ }
+
+ private def servletContext(implicit servlets: Map[String, ServletHolder],
+ filters: Map[String, FilterHolder]) = {
+ val context = new ServletContextHandler()
+
+ for ((pathSpec, servlet) <- servlets) {
+ context.addServlet(servlet, pathSpec)
+ }
+
+ for ((pathSpec, filter) <- filters) {
+ context.addFilter(filter, pathSpec, EnumSet.of(DispatcherType.REQUEST))
+ }
+
+ context.setConnectorNames(Array("main"))
+ context
+ }
+
+ private def internalServletContext = {
+ val internalContext = new ServletContextHandler()
+ internalContext.addServlet(new ServletHolder(new MetricsServlet), "/*")
+ internalContext.setConnectorNames(Array("internal"))
+ internalContext
+ }
+}
View
24 src/main/scala/com/yammer/dropwizard/jersey/ScanningGuiceContainer.scala
@@ -1,24 +0,0 @@
-package com.yammer.dropwizard.jersey
-
-import com.google.inject.{Inject, Injector, Singleton}
-import java.io.File
-import com.sun.jersey.api.core.{ResourceConfig, ClasspathResourceConfig}
-import com.sun.jersey.guice.spi.container.servlet.GuiceContainer
-import com.sun.jersey.spi.container.servlet.WebConfig
-
-/**
- * A Guice Jersey container which scans the entire classpath for @Path
- * and @Provider annotated classes.
- *
- * @author coda
- */
-@Singleton
-class ScanningGuiceContainer @Inject() (injector: Injector) extends GuiceContainer(injector) {
- override def getDefaultResourceConfig(props: java.util.Map[String, Object], webConfig: WebConfig) = {
- val config = new ClasspathResourceConfig(classpath)
- config.getFeatures.put(ResourceConfig.FEATURE_DISABLE_WADL, true)
- config
- }
-
- private def classpath = System.getProperty("java.class.path").split(File.pathSeparator)
-}
View
23 src/main/scala/com/yammer/dropwizard/lifecycle/JettyManager.scala
@@ -1,22 +1,13 @@
package com.yammer.dropwizard.lifecycle
-import collection.JavaConversions._
-import org.eclipse.jetty.util.component.{LifeCycle, AbstractLifeCycle}
-import com.google.inject.{Key, TypeLiteral, ConfigurationException, Injector}
-
-object JettyManager {
- def collect(injector: Injector): Seq[LifeCycle] = {
- try {
- val manageds = injector.getInstance(Key.get(new TypeLiteral[java.util.Set[Managed]]() {}))
- manageds.map { m => new JettyManager(m) }.toSeq
- } catch {
- case e: ConfigurationException => Nil
- }
- }
-}
+import org.eclipse.jetty.util.component.AbstractLifeCycle
class JettyManager(m: Managed) extends AbstractLifeCycle {
- override def doStop() = m.stop()
+ override def doStop() {
+ m.stop()
+ }
- override def doStart() = m.start()
+ override def doStart() {
+ m.start()
+ }
}
View
49 src/main/scala/com/yammer/dropwizard/modules/ConfigurationModule.scala
@@ -1,49 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import com.codahale.fig.Configuration
-import java.util.logging.Logger
-import org.slf4j.bridge.SLF4JBridgeHandler
-import com.codahale.logula.Logging
-import org.apache.log4j.Level
-
-class ConfigurationModule(filename: String) extends GuiceModule {
- private val config = new Configuration(filename)
- val rootLogger = Logger.getLogger("")
- rootLogger.getHandlers.foreach(rootLogger.removeHandler)
- rootLogger.addHandler(new SLF4JBridgeHandler)
- Logging.configure { log =>
- log.registerWithJMX = true
-
- log.level = Level.toLevel(config("logging.level").or("info"), Level.INFO)
-
- for ((name, level) <- config("logging.loggers").asMap[String]) {
- log.loggers(name.toString) = Level.toLevel(level, Level.INFO)
- }
-
- log.console.enabled = config("logging.console.enabled").or(true)
-
- config("logging.console.threshold").asOption[String].foreach {l =>
- log.console.threshold = Level.toLevel(l, Level.ALL)
- }
-
- if (config("logging.file.enabled").or(false)) {
- log.file.enabled = true
- log.file.filename = config("logging.file.filename").asRequired[String]
- log.file.maxSize = config("logging.file.max_log_size_kilobytes").or(10240)
- log.file.retainedFiles = config("logging.file.retain_files").or(1)
- config("logging.file.threshold").asOption[String].foreach {l =>
- log.file.threshold = Level.toLevel(l, Level.ALL)
- }
- }
-
- if (config("logging.syslog.enabled").or(false)) {
- log.syslog.enabled = true
- log.syslog.host = config("logging.syslog.host").asRequired[String]
- log.syslog.facility = config("logging.syslog.facility").asRequired[String]
- }
- }
-
- def configure {
- bind[Configuration].toInstance(config)
- }
-}
View
25 src/main/scala/com/yammer/dropwizard/modules/GuiceModule.scala
@@ -1,25 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import com.google.inject.AbstractModule
-import com.google.inject.binder.{LinkedBindingBuilder, ScopedBindingBuilder, AnnotatedBindingBuilder}
-import com.google.inject.multibindings.Multibinder
-
-/**
- * A Scala-friendly wrapper for common Guice bindings.
- *
- * @author coda
- */
-abstract class GuiceModule extends AbstractModule {
- implicit def linkedBindingBuilder2scalaBuilder[A](builder: LinkedBindingBuilder[A]) = new {
- def to[T <: A](implicit mf: Manifest[T]): ScopedBindingBuilder = builder.to(mf.erasure.asInstanceOf[Class[A]])
-
- def providedBy[T](implicit mf: Manifest[T]) = "poop"
- }
-
- protected def bind[A](implicit mf: Manifest[A]): AnnotatedBindingBuilder[A] = bind(mf.erasure.asInstanceOf[Class[A]])
-
- protected def multibind[A](f: Multibinder[A] => Any)(implicit mf: Manifest[A]) {
- val multi = Multibinder.newSetBinder(binder, mf.erasure.asInstanceOf[Class[A]])
- f(multi)
- }
-}
View
11 src/main/scala/com/yammer/dropwizard/modules/GuiceMultibindingModule.scala
@@ -1,11 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import com.google.inject.multibindings.Multibinder
-
-
-class GuiceMultibindingModule[A](interface: Class[A], implementations: Class[_ <: A]*) extends GuiceModule {
- def configure = {
- val multibinder = Multibinder.newSetBinder(binder, interface)
- implementations.foreach { multibinder.addBinding.to(_).asEagerSingleton }
- }
-}
View
31 src/main/scala/com/yammer/dropwizard/modules/GuiceServletModule.scala
@@ -1,31 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import scala.collection.JavaConversions.asJavaMap
-import javax.servlet.Filter
-import javax.servlet.http.HttpServlet
-import com.google.inject.servlet.ServletModule
-import com.google.inject.servlet.ServletModule.{ServletKeyBindingBuilder, FilterKeyBindingBuilder}
-
-/**
- * A Scala-friendly wrapper for common Guice servlet bindings.
- *
- * @author coda
- */
-class GuiceServletModule extends ServletModule {
- implicit def servletKeyBindingBuilder2scalaBuilder(builder: ServletKeyBindingBuilder) = new {
- def using[A <: HttpServlet](implicit mf: Manifest[A]): Unit =
- builder.`with`(mf.erasure.asInstanceOf[Class[HttpServlet]])
-
- def using[A <: HttpServlet](initParams: Map[String, String])(implicit mf: Manifest[A]): Unit =
- builder.`with`(mf.erasure.asInstanceOf[Class[HttpServlet]], asJavaMap(initParams))
- }
-
- implicit def filterKeyBindingBuilder2scalaBuilder(builder: FilterKeyBindingBuilder) = new {
- def through[A <: Filter](implicit mf: Manifest[A]): Unit =
- builder.through(mf.erasure.asInstanceOf[Class[Filter]])
-
- def through[A <: Filter](initParams: Map[String, String])(implicit mf: Manifest[A]): Unit =
- builder.through(mf.erasure.asInstanceOf[Class[Filter]], asJavaMap(initParams))
- }
-}
-
View
11 src/main/scala/com/yammer/dropwizard/modules/JerseyServletModule.scala
@@ -1,11 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import com.yammer.dropwizard.jersey.ScanningGuiceContainer
-
-case class JerseyServletModule(rootUri: String) extends GuiceServletModule {
- override def configureServlets = {
- serve(rootUri).using[ScanningGuiceContainer]
- }
-
- override def toString = "%s(%s)".format(getClass.getCanonicalName, rootUri)
-}
View
9 src/main/scala/com/yammer/dropwizard/modules/ProviderModule.scala
@@ -1,9 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import com.google.inject.AbstractModule
-
-abstract class ProviderModule extends AbstractModule {
- def configure = {}
-
- override def toString = getClass.getCanonicalName
-}
View
89 src/main/scala/com/yammer/dropwizard/modules/ServerModule.scala
@@ -1,89 +0,0 @@
-package com.yammer.dropwizard.modules
-
-import com.codahale.fig.Configuration
-import org.eclipse.jetty.util.thread.QueuedThreadPool
-import org.eclipse.jetty.server.bio.SocketConnector
-import org.eclipse.jetty.server.nio.{SelectChannelConnector, BlockingChannelConnector}
-import com.google.inject.{Injector, Singleton, Provides}
-import org.eclipse.jetty.server.handler.{HandlerCollection, RequestLogHandler}
-import com.yammer.metrics.jetty.InstrumentedHandler
-import org.eclipse.jetty.servlet.{DefaultServlet, FilterMapping, ServletContextHandler, ServletHolder}
-import com.google.inject.servlet.{GuiceServletContextListener, GuiceFilter}
-import org.eclipse.jetty.server.{Connector, Server}
-import com.yammer.metrics.reporting.MetricsServlet
-
-class ServerModule extends ProviderModule {
- @Provides
- @Singleton
- def provideServer(config: Configuration, injector: Injector): Server = {
- val server = makeServer(config, mainConnector(config), internalConnector(config))
-
- val handlers = new HandlerCollection
- handlers.addHandler(new InstrumentedHandler(servletContext(injector)))
- handlers.addHandler(internalServletContext)
- if (config("request_log.enabled").or(false)) {
- handlers.addHandler(injector.getInstance(classOf[RequestLogHandler]))
- }
- server.setHandler(handlers)
-
- server
- }
-
- private def newConnector(config: Configuration) = config("http.connector").or("blocking_channel") match {
- case "socket" => new SocketConnector
- case "select_channel" => new SelectChannelConnector
- case "blocking_channel" => new BlockingChannelConnector
- }
-
- private def mainConnector(config: Configuration) = {
- val port = config("http.port").or(8080)
- val connector = newConnector(config)
- config("http.hostname").asOption[String].foreach(connector.setHost)
- connector.setForwarded(config("http.forwarded").or(false))
- connector.setPort(port)
- connector.setName("main")
- connector
- }
-
- private def makeServer(config: Configuration, connectors: Connector*) = {
- val server = new Server
- connectors.foreach(server.addConnector)
- server.setSendServerVersion(false)
- server.setThreadPool(makeThreadPool(config))
- server.setStopAtShutdown(true)
- server.setGracefulShutdown(config("http.shutdown_milliseconds").or(2000))
- server
- }
-
- private def makeThreadPool(config: Configuration) = {
- val pool = new QueuedThreadPool
- config("http.max_connections").asOption[Int].foreach(pool.setMaxThreads)
- config("http.min_connections").asOption[Int].foreach(pool.setMinThreads)
- pool
- }
-
- private def internalConnector(config: Configuration) = {
- val connector = newConnector(config)
- connector.setPort(config("metrics.port").or(8081))
- connector.setName("internal")
- connector
- }
-
- private def servletContext(injector: Injector) = {
- val context = new ServletContextHandler()
- context.addFilter(classOf[GuiceFilter], "/*", FilterMapping.DEFAULT)
- context.addEventListener(new GuiceServletContextListener {
- def getInjector = injector
- })
- context.addServlet(classOf[DefaultServlet], "/")
- context.setConnectorNames(Array("main"))
- context
- }
-
- private def internalServletContext = {
- val internalContext = new ServletContextHandler()
- internalContext.addServlet(new ServletHolder(new MetricsServlet), "/*")
- internalContext.setConnectorNames(Array("internal"))
- internalContext
- }
-}
View
2 ...izard/jersey/LoggingExceptionMapper.scala → ...rd/providers/LoggingExceptionMapper.scala
@@ -1,4 +1,4 @@
-package com.yammer.dropwizard.jersey
+package com.yammer.dropwizard.providers
import util.Random
import javax.ws.rs.WebApplicationException
View
10 src/main/scala/com/yammer/dropwizard/service/Jersey.scala
@@ -1,10 +0,0 @@
-package com.yammer.dropwizard.service
-
-import com.yammer.dropwizard.modules.JerseyServletModule
-import com.yammer.dropwizard.Service
-
-trait Jersey extends Service {
- def rootUri = "/*"
-
- require(new JerseyServletModule(rootUri))
-}
View
78 src/main/scala/com/yammer/dropwizard/util/QuietErrorHandler.scala
@@ -0,0 +1,78 @@
+package com.yammer.dropwizard.util
+
+import annotation.switch
+import java.io.Writer
+import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
+import org.eclipse.jetty.server.handler.ErrorHandler
+import org.eclipse.jetty.http.HttpGenerator
+
+class QuietErrorHandler extends ErrorHandler {
+ import HttpServletResponse._
+
+ private def errorMessage(request: HttpServletRequest, code: Int) =
+ (code: @switch) match {
+ case SC_BAD_REQUEST =>
+ "Your HTTP client sent a request that this server could not understand."
+ case SC_CONFLICT =>
+ "The request could not be completed due to a conflict with the " +
+ "current state of the resource."
+ case SC_EXPECTATION_FAILED =>
+ "The server could not meet the expectation given in the Expect " +
+ "request header."
+ case SC_FORBIDDEN =>
+ "You don't have permission to access the requested resource."
+ case SC_GONE =>
+ "The requested resource used to exist but no longer does."
+ case SC_INTERNAL_SERVER_ERROR =>
+ "The server encountered an internal error and was unable to complete" +
+ " your request."
+ case SC_LENGTH_REQUIRED =>
+ ("A request with the %s method requires a valid Content-Length" +
+ " header.").format(request.getMethod)
+ case SC_METHOD_NOT_ALLOWED =>
+ ("The %s method is not allowed for the requested " +
+ "resouce.").format(request.getMethod)
+ case SC_NOT_ACCEPTABLE =>
+ "The resource identified by the request is only capable of generating" +
+ " response entities which have content characteristics not" +
+ " acceptable according to the accept headers sent in the request."
+ case SC_NOT_FOUND =>
+ "The requested resource could not be found on this server."
+ case SC_OK =>
+ ""
+ case SC_PRECONDITION_FAILED =>
+ "The precondition on the request for the resource failed positive" +
+ " evaluation."
+ case SC_REQUEST_ENTITY_TOO_LARGE =>
+ ("The %s method does not allow the data transmitted, or the data" +
+ " volume exceeds the capacity limit.").format(request.getMethod)
+ case SC_REQUEST_TIMEOUT =>
+ "The server closed the network connection because your HTTP client" +
+ " didn't finish the request within the specified time."
+ case SC_REQUEST_URI_TOO_LONG =>
+ "The length of the requested URL exceeds the capacity limit for this" +
+ " server. The request cannot be processed."
+ case SC_REQUESTED_RANGE_NOT_SATISFIABLE =>
+ "The server cannot serve the requested byte range."
+ case SC_SERVICE_UNAVAILABLE =>
+ "The server is temporarily unable to service your request due to" +
+ " maintenance downtime or capacity problems. Please try again later."
+ case SC_UNAUTHORIZED =>
+ "This server could not verify that you are authorized to access" +
+ " this resource.\n" +
+ "You either supplied the wrong credentials (e.g., bad password)," +
+ " or your HTTP client doesn't understand how to supply the" +
+ " required credentials."
+ case SC_UNSUPPORTED_MEDIA_TYPE =>
+ "The server does not support the media type transmitted in the request."
+ case status =>
+ "Your request could not be processed: " + HttpGenerator.getReasonBuffer(status)
+ }
+
+ override def handleErrorPage(request: HttpServletRequest,
+ writer: Writer,
+ code: Int,
+ message: String) {
+ writer.append(errorMessage(request, code)).append("\n\n")
+ }
+}
View
30 src/test/resources/example.conf
@@ -6,14 +6,34 @@
// "socket".
"connector": "blocking_channel",
+ // The maximum idle time for a connection. Only valid for select_channel
+ // connector.
+ //"max_idle_time_seconds": 300,
+
+ // The number of acceptor threads to set. Only valid for select_channel
+ // connector.
+ //"acceptor_threads": 2,
+
+ // Set the number of connections, which if exceeded places the manager in
+ // low resources state. This is not an exact measure as the connection count
+ // is averaged over the select sets. Only valid for select_channel
+ // connector.
+ //"low_resources_connections": 25000,
+
+ // The amount of time that a connection is allowed to be idle when there are
+ // more than `low_resources_connections` connections. This allows the server
+ // to rapidly close idle connections in order to gracefully handle high load
+ // situations. Only valid for select_channel connector.
+ //"low_resources_max_idle_time_seconds": 5,
+
// The TCP/IP port Jetty will host your server on.
"port": 8080,
- // Maximum number of concurrent connections.
- "max_connections": 50,
+ // Maximum number of threads.
+ "max_threads": 50,
// Minimum number of thread to keep alive.
- "min_connections": 10,
+ "min_threads": 10,
// Number of milliseconds to wait for connections to complete while
// gracefully shutting down.
@@ -54,7 +74,7 @@
"enabled": false,
// The filename pattern for the log file.
- "filename": "./logs/notifications.log",
+ "filename": "./logs/example.log",
// Let logs get to 50MB in size.
"max_log_size_kilobytes": 51200,
@@ -90,7 +110,7 @@
"extended": false,
// URIs which will not be logged.
- "ignore_paths": ["/health"],
+ "ignore_paths": [],
// Whether to log cookie values.
"include_cookies": false,
View
18 src/test/scala/com/yammer/dropwizard/examples/Example.scala
@@ -1,9 +1,9 @@
package com.yammer.dropwizard.examples
-import com.yammer.dropwizard.Service
-import com.yammer.dropwizard.service.Jersey
+import com.codahale.fig.Configuration
+import com.yammer.dropwizard.{Environment, Service}
-object Example extends Service with Jersey {
+object Example extends Service {
def name = "Example"
override def banner = Some("""
@@ -16,9 +16,13 @@ object Example extends Service with Jersey {
88
dP
""")
-
- require(new SayingModule)
+
provide(new SayCommand, new SplodyCommand)
- manage[StartableObject]
- healthCheck[DumbHealthCheck]
+
+ def configure(implicit config: Configuration, environment: Environment) {
+ implicit val template = SayingFactory.buildSaying
+ environment.addResource(new HelloWorldResource)
+ environment.addHealthCheck(new DumbHealthCheck)
+ environment.manage(new StartableObject)
+ }
}
View
17 src/test/scala/com/yammer/dropwizard/examples/HelloWorldResource.scala
@@ -1,13 +1,18 @@
package com.yammer.dropwizard.examples
-import javax.ws.rs.{Produces, GET, Path}
-import javax.ws.rs.core.MediaType
-import com.google.inject.{Singleton, Inject}
+import javax.ws.rs._
+import core.Response.Status
+import core.{Response, MediaType}
@Path("/hello-world")
@Produces(Array(MediaType.APPLICATION_JSON))
-@Singleton
-class HelloWorldResource @Inject() (saying: String) {
+class HelloWorldResource(implicit saying: String) {
@GET
- def sayHello = Seq(saying)
+ def sayHello(@QueryParam("opt") opt: Option[String]) = Seq(saying)
+
+ @POST
+ def intentionalError = Response.status(Status.BAD_REQUEST).build()
+
+ @PUT
+ def unintentionalError = None.get
}
View
9 src/test/scala/com/yammer/dropwizard/examples/SayCommand.scala
@@ -1,17 +1,18 @@
package com.yammer.dropwizard.examples
import com.yammer.dropwizard.cli.{Flag, ConfiguredCommand}
+import com.yammer.dropwizard.Service
+import com.codahale.fig.Configuration
class SayCommand extends ConfiguredCommand {
def name = "say"
override def description = Some("Prints out the saying to console")
override def options = Flag("v", "verbose", "yell it a lot") :: Nil
-
- def runWithConfigFile(opts: Map[String, List[String]],
- args: List[String]) = {
- val saying = injector.getInstance(classOf[String])
+
+ def run(service: Service, config: Configuration, opts: Map[String, List[String]], args: List[String]) = {
+ val saying = SayingFactory.buildSaying(config)
for (i <- 1 to (if (opts.contains("verbose")) 10 else 1)) {
log.warn(saying)
}
View
7 src/test/scala/com/yammer/dropwizard/examples/SayingFactory.scala
@@ -0,0 +1,7 @@
+package com.yammer.dropwizard.examples
+
+import com.codahale.fig.Configuration
+
+object SayingFactory {
+ def buildSaying(implicit config: Configuration) = config("saying").asRequired[String]
+}
View
16 src/test/scala/com/yammer/dropwizard/examples/SayingModule.scala
@@ -1,16 +0,0 @@
-package com.yammer.dropwizard.examples
-
-import com.codahale.fig.Configuration
-import com.google.inject.{Singleton, Provides}
-import com.yammer.dropwizard.modules.ProviderModule
-
-class SayingModule extends ProviderModule {
- @Provides
- @Singleton
- def provideSaying(config: Configuration): String = config("saying").asRequired[String]
-
- @Provides
- def shouldNeverBeCalled(confi: Configuration): Int = {
- throw new RuntimeException("this should never be called")
- }
-}
View
11 src/test/scala/com/yammer/dropwizard/examples/SplodyCommand.scala
@@ -1,6 +1,7 @@
package com.yammer.dropwizard.examples
import com.yammer.dropwizard.cli.{Flag, FlagGroup, Command}
+import com.yammer.dropwizard.Service
class SplodyCommand extends Command {
def name = "splody"
@@ -9,22 +10,16 @@ class SplodyCommand extends Command {
override def options =
FlagGroup(Seq(Flag("r", "required", "a required option")),required = true) ::
- Flag("g", "guice", "do something dumb with Guice") ::
Flag("e", "exception", "throw an exception") ::
Flag("m", "message", "return an error message") ::
Nil
- def run(opts: Map[String, List[String]], args: List[String]) = {
- if (opts.contains("guice")) {
- println("Using the injector to get an instance of something Guice doesn't know about")
- injector.getInstance(classOf[Command])
- }
-
+ def run(service: Service, opts: Map[String, List[String]], args: List[String]) = {
if (opts.contains("exception")) {
println("Throwing an exception")
error("EXPERIENCE BIJ")
}
-
+
opts.get("message").map { _ => "Y U NO DO RIGHT THING" }
}
}
View
3 src/test/scala/com/yammer/dropwizard/examples/StartableObject.scala
@@ -1,10 +1,9 @@
package com.yammer.dropwizard.examples
import com.codahale.logula.Logging
-import com.google.inject.Inject
import com.yammer.dropwizard.lifecycle.Managed
-class StartableObject @Inject()(template: String) extends Managed with Logging {
+class StartableObject(implicit template: String) extends Managed with Logging {
override def start() {
log.info("Starting: %s", template)
}

0 comments on commit 6e1764f

Please sign in to comment.