dropwizard / dropwizard Goto Github PK
View Code? Open in Web Editor NEWA damn simple library for building production-ready RESTful web services.
Home Page: https://www.dropwizard.io
License: Apache License 2.0
A damn simple library for building production-ready RESTful web services.
Home Page: https://www.dropwizard.io
License: Apache License 2.0
No need to keep this around in the critical path. We should generate the log statement and then push it to a queue for a background thread to write to disk.
Just some non configurable roadblocks I've hit:
Just tried to build from latest GIT, but HttpClient support fails:
Running com.yammer.metrics.httpclient.tests.InstrumentedHttpClientTest
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.247 sec
Running com.yammer.metrics.httpclient.tests.InstrumentedClientConnManagerTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.023 sec <<< FAILURE!
Results :
Failed tests:
what(com.yammer.metrics.httpclient.tests.InstrumentedClientConnManagerTest):
Expected: is 1
got: 0
DW >= 0.2.0 breaks config parsing. I have the following configuration classes for my (Scala) service:
class CryptoConfiguration extends Configuration {
var keyStore = "key.store"
var keyPass = ""
var algo = ""
var keySize: Int = 0
}
class ExternalServiceConfiguration extends Configuration {
var api: URL = new URL("http://wrongo:1234")
var user = ""
var pass = ""
}
class ServiceConfiguration extends Configuration {
var database = new DatabaseConfiguration()
var rabbit = new RabbitConfiguration()
var cachet = new CachetConfiguration()
var s3 = new S3Configuration()
var crypto = new CryptoConfiguration()
var api = new URL("http://fixme")
}
And here's the config.yml:
http:
port: 12004
adminPort: 12005
maxIdleTime: 30s
requestLog:
enabled: true
rabbit:
host: localhost
vhost: /local/myservice
username: myservice
password: myservice
database:
url: jdbc:postgresql://localhost/myservice
username: myservice
password: myservice
externalservice:
api: https://externalservice.com
user: elided
pass: elided
# Logging settings.
logging:
level: DEBUG
console:
enabled: true
threshold: DEBUG
syslog:
enabled: false
loggers:
org.apache.http.wire: WARN
org.eclipse.jetty.http.HttpParser: WARN
org.apache.http.headers: DEBUG
org.eclipse.jetty.server.AbstractHttpConnection: WARN
org.eclipse.jetty.server.handler.ContextHandler: WARN
org.eclipse.jetty.io.nio.ChannelEndPoint: WARN
org.eclipse.jetty.servlet.ServletHandler: WARN
org.eclipse.jetty.server.AbstractConnector: WARN
org.eclipse.jetty.util.component.AbstractLifeCycle: WARN
org.eclipse.jetty.util.component.Container: WARN
file:
enabled: true
threshold: ALL
filenamePattern: ./logs/myservice.log
s3:
bucket: myservice-dev
key: elidedd
secret: elided
crypto:
keyStore: key.store
keyPass: elided
algo: Blowfish
keySize: 256
api: http://randomhost
When I start the service, it dies with:
Exception in thread "main" org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "rabbit" (Class com.simple.clownshoes.config.ServiceConfiguration), not marked as ignorable
at [Source: N/A; line: -1, column: -1] (through reference chain: com.simple.clownshoes.config.ServiceConfiguration["rabbit"])
at org.codehaus.jackson.map.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:53)
at org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:267)
at org.codehaus.jackson.map.deser.std.StdDeserializer.reportUnknownProperty(StdDeserializer.java:672)
at org.codehaus.jackson.map.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:658)
at org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:1361)
at org.codehaus.jackson.map.deser.BeanDeserializer._handleUnknown(BeanDeserializer.java:725)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:703)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2704)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1999)
at com.yammer.dropwizard.json.Json.readYamlValue(Json.java:508)
at com.yammer.dropwizard.config.ConfigurationFactory.parse(ConfigurationFactory.java:43)
at com.yammer.dropwizard.config.ConfigurationFactory.build(ConfigurationFactory.java:36)
at com.yammer.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:69)
at com.yammer.dropwizard.cli.Command.run(Command.java:112)
at com.yammer.dropwizard.AbstractService.run(AbstractService.java:178)
at com.yammer.dropwizard.ScalaService.main(ScalaService.scala:13)
Everything works fine on 0.1.3.
Since Dropwizard supports AssetsBundle
s, I thought that maybe this would be a quick way to test out them fancy JS frontends (Backbone, Ember, etc.) by throwing them up on src/main/resources/assets
and trying to serve from there. However, I quickly realized that Dropwizard either doesn't reload any of the resources it gets, or I'm missing something on configuring it to reload static assets.
If I were using the Maven Jetty plugin, I'd throw something in the config to use a custom webdefault.xml
file as described here for us lowly Windows users: http://docs.codehaus.org/display/JETTY/Files+locked+on+Windows
Is this something I can do in Dropwizard, or is this too far out of scope for the tool?
DropWizard is awesome! Thanks for such a productivity booster! Even so, I found a little gotcha to share...
DropWizard should automatically log exceptions to console without the user needing to manually insert try-catch-log boilerplate to every resource method. This would reduce plumbing and improve usability.
I have the following gcwizard.yml config file:
logging:
console:
# If true, write log statements to stdout.
enabled: true
# Do not display log statements below this threshold to stdout.
threshold: TRACE
… and there's a server resource with a simple method like so:
@get
@timed
@ExceptionMetered
public Saying sayHello(@QueryParam("name") Optional name) {
// try {
dumpMetrics();
return new Saying(counter.incrementAndGet(), String.format(template, name.or(defaultName)));
// } catch (Throwable e) {
// LOG.error(e, "gcwizard error in sayHello");
// throw new RuntimeException(e);
// }
}
When I call the service curl tells me that something failed, but it turns out the dropwizard service didn't log any stacktrace:
$ curl http://localhost:8080/gcwizard?name=foo
There was an error processing your request. It has been logged (ID 46b4c2d7ea57bef0).
DropWizard console output isn't very helpful to diagnose the problem:
…
INFO [2012-06-11 01:23:54,919] org.eclipse.jetty.server.AbstractConnector: Started [email protected]:8080
INFO [2012-06-11 01:23:54,923] org.eclipse.jetty.server.AbstractConnector: Started [email protected]:8081
0:0:0:0:0:0:0:1%0 - - [11/Jun/2012:01:23:57 +0000] "GET /gcwizard?name=foo HTTP/1.1" 400 72 2152 2152
Now, if I uncomment the try-catch-LOG block above and rerun I can see the stacktrace to diagnose the problem (see output further below). With this stacktrace I was easily able to fix my bug in calling some third party REST service (fix was to ask jackson to map JSON to Map.class instead of String.class). However, I believe I shouldn't have to manually add that try-catch-log boilerplate to every resource method since the doc at http://dropwizard.codahale.com/manual/core/#logging nicely promises to already do this:
"Error Handling :If your resource class unintentionally throws an exception, Dropwizard will log that exception (including stack traces) and return a terse, safe text/plain 500 Internal Server Error response."
What am I missing?
FYI, here is what my manual try-catch-log statement prints:
…
INFO [2012-06-11 01:22:54,639] org.eclipse.jetty.server.AbstractConnector: Started [email protected]:8080
INFO [2012-06-11 01:22:54,642] org.eclipse.jetty.server.AbstractConnector: Started [email protected]:8081
ERROR [2012-06-11 01:22:58,720] com.alpinefex.gcwizard.GCWizardResource: gcwizard error in sayHello
! javax.ws.rs.WebApplicationException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:103)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.readFrom(JacksonMessageBodyProvider.java:82)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:554)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
! at com.sun.jersey.api.client.WebResource.handle(WebResource.java:684)
! at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
! at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
! at com.alpinefex.gcwizard.GCWizardResource.dumpMetrics(GCWizardResource.java:84)
! at com.alpinefex.gcwizard.GCWizardResource.sayHello(GCWizardResource.java:72)
! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
! at java.lang.reflect.Method.invoke(Method.java:597)
! at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
! at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
! at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$TimedRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:34)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$ExceptionMeteredRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:73)
! at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
! at com.sun.jersey.server.impl.uri.rules.ResourceObjectRule.accept(ResourceObjectRule.java:100)
! at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
! at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
! at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
! at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
! at com.yammer.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:47)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1367)
! at com.yammer.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:29)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1338)
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:484)
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at com.yammer.metrics.jetty.InstrumentedHandler.handle(InstrumentedHandler.java:200)
! at org.eclipse.jetty.server.handler.GzipHandler.handle(GzipHandler.java:270)
! at com.yammer.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:123)
! at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at org.eclipse.jetty.server.Server.handle(Server.java:350)
! at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
! at org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:47)
! at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:890)
! at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:944)
! at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:630)
! at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:230)
! at org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:66)
! at org.eclipse.jetty.server.nio.BlockingChannelConnector$BlockingChannelEndPoint.run(BlockingChannelConnector.java:293)
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:603)
! at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:538)
! at java.lang.Thread.run(Thread.java:680)
Caused by: ! org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
! at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:219)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:44)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:13)
! at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2732)
! at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1923)
! at com.yammer.dropwizard.json.Json.readValue(Json.java:335)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:101)
!... 56 common frames omitted
ERROR [2012-06-11 01:22:58,722] com.yammer.dropwizard.jersey.LoggingExceptionMapper: Error handling a request: 46b4c2d7ea57bef0
! java.lang.RuntimeException: javax.ws.rs.WebApplicationException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at com.alpinefex.gcwizard.GCWizardResource.sayHello(GCWizardResource.java:76)
! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
! at java.lang.reflect.Method.invoke(Method.java:597)
! at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
! at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
! at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$TimedRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:34)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$ExceptionMeteredRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:73)
! at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
! at com.sun.jersey.server.impl.uri.rules.ResourceObjectRule.accept(ResourceObjectRule.java:100)
! at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
! at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
! at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
! at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
! at com.yammer.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:47)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1367)
! at com.yammer.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:29)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1338)
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:484)
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at com.yammer.metrics.jetty.InstrumentedHandler.handle(InstrumentedHandler.java:200)
! at org.eclipse.jetty.server.handler.GzipHandler.handle(GzipHandler.java:270)
! at com.yammer.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:123)
! at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at org.eclipse.jetty.server.Server.handle(Server.java:350)
! at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
! at org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:47)
! at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:890)
! at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:944)
! at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:630)
! at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:230)
! at org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:66)
! at org.eclipse.jetty.server.nio.BlockingChannelConnector$BlockingChannelEndPoint.run(BlockingChannelConnector.java:293)
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:603)
! at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:538)
! at java.lang.Thread.run(Thread.java:680)
Caused by: ! javax.ws.rs.WebApplicationException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:103)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.readFrom(JacksonMessageBodyProvider.java:82)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:554)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
! at com.sun.jersey.api.client.WebResource.handle(WebResource.java:684)
! at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
! at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
! at com.alpinefex.gcwizard.GCWizardResource.dumpMetrics(GCWizardResource.java:84)
! at com.alpinefex.gcwizard.GCWizardResource.sayHello(GCWizardResource.java:72)
!... 48 common frames omitted
Caused by: ! org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
! at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:219)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:44)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:13)
! at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2732)
! at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1923)
! at com.yammer.dropwizard.json.Json.readValue(Json.java:335)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:101)
!... 56 common frames omitted
0:0:0:0:0:0:0:1%0 - - [11/Jun/2012:01:22:56 +0000] "GET /gcwizard?name=foo HTTP/1.1" 500 86 2587 2587
Keep in mind we'll need to provide the ability for consumers like ConfigurationFactory
to customize behavior (e.g., failing on unknown properties).
Hi,
I was going through the user manual specifically
http://dropwizard.codahale.com/manual/testing/
The Json helper function over there is indicated as asJSON whereas it should be asJson, this seems to be fixed in the repository but somehow doesn't reflect on the site.
java -jar dropwizard-core-0.2.0-SNAPSHOT.jar <command> [arg1 arg2]
You are not the right JAR!
Getting the Missing Template error when I place the template in classpath relative to the View class, e.g. src/main/resources/my/package/ViewClass/view.ftl
I was able to resolve it finally by placing the view.ftl in src/main/resources (root of the classpath)
While debugging the template I encounter following in ViewMessageBodyWriter.java:
38: configuration.setClassForTemplateLoading(key, "/");
If I change this invocation to configuration.setClassForTemplateLoading(key, ""), things work almost as documented, i.e. the template file is picked up from: src/main/resources/my/package/view.ftl (I have also found that this may, in fact, be preferable to .../my/package/View/view.ftl since eclipse flags a warning on the View class "The type View collides with a package")
I have a class defined like:
@Path("/locations")
@Produces(Array(MediaType.APPLICATION_JSON + ";charset=utf-8"))
class LocationsResource(httpClient:HttpClient){
@GET
@Path("/search")
@Timed
def search(@QueryParam("ll") ll:String, @QueryParam("q") query:Option[String]):Response = {
}
@GET
@Path("/details")
@Timed
def details(@QueryParam("venue_id") VenueIdOpt:Option[String]):Response = {
}
}
The routes display:
GET /locations (xxx.LocationsResource)
GET /locations (xxx.LocationsResource)
When it should show the path for each method: GET /locations/search
Here's a resource
package com.scala.aboutdropwizard
import javax.ws.rs.core.MediaType
import javax.ws.rs.{GET, Produces, Path}
case class DumbResult(val itIsOk: Boolean)
@Path("/hello-scala-world")
@Produces(Array(MediaType.APPLICATION_JSON))
class HelloScalaWorldResource {
@GET def wellHello(): DumbResult = {
DumbResult(true)
}
}
And a scala service:
package com.scala.aboutdropwizard
import scala.collection.mutable.ArrayBuilder
import com.aboutdropwizard._
import com.yammer.dropwizard.Service
import com.yammer.dropwizard.config.Environment
class HelloScalaWorldService extends Service[HelloWorldConfiguration]("The scala hello world") {
def initialize(config: HelloWorldConfiguration, environment: Environment) {
val template = config.getTemplate
val defaultName = config.getDefaultName
environment.addResource(new HelloWorldResource(template, defaultName));
environment.addResource(new HelloScalaWorldResource)
environment.addHealthCheck(new TemplateHealthCheck(template));
}
}
object HelloScalaWorldService {
def main(args: Array[String]) = new HelloScalaWorldService().run(args)
}
Doing curl -v http://127.0.0.1:8080/hello-scala-world
produces the following error:
ERROR [2012-01-25 00:11:33,141] com.sun.jersey.spi.container.ContainerResponse: A message body writer for Java class com.scala.aboutdropwizard.DumbResult, and Java type class com.scala.aboutdropwizard.DumbResult, and MIME media type application/json was not found
ERROR [2012-01-25 00:11:33,142] com.sun.jersey.spi.container.ContainerResponse: The registered message body writers compatible with the MIME media type are:
application/json ->
com.yammer.dropwizard.jersey.JacksonMessageBodyProvider
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.ReaderProvider
com.sun.jersey.core.impl.provider.entity.DocumentProvider
com.sun.jersey.core.impl.provider.entity.StreamingOutputProvider
com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
com.sun.jersey.server.impl.template.ViewableMessageBodyWriter
com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
The java version of the resource works fine.
Using @produces(MediaType.APPLICATION_JSON) in scala instead of @produces(Array(MediaType.APPLICATION_JSON)) produces compile-time error
[ERROR] found : java.lang.String("application/json")
[ERROR] required: Array[java.lang.String]
[ERROR] @Produces(MediaType.APPLICATION_JSON)
I'm at a loss w.r.t. what's going on. Any suggestions?
I am trying to change default settings for some of DropWizard Configuration settings (specifically, disabling default gzip handling to customize it). This seemed simple: in default constructor of my sub-class I just tweak properties.
But the snatch is that properties are typically declared as private, and there are no mutators.
My first inclination is to change properties to protected, so that my sub-class can change their values.
Alternatively I could add mutator(s), but this seems bit more convoluted. And changing access to protected would also make it possible for sub-classes to add mutators by those who... like, like adding setXxx() methods.
If this does not sounds like a colossally bad idea, I'll submit a patch for this.
There are issues with admin tasks when running the application and admin contexts off the same port. For example:
curl -X POST http://localhost:8081/tasks/build-index
works great. But if I use the same port in configuration yaml:
http:
port: 8080
adminPort: 8080
curl -X POST http://localhost:8080/admin/tasks/build-index
gives me a 404
I know that the admin context path is correct because my health checks work:
curl http://localhost:8080/admin/healthcheck
On a previous project (not using dropwizard) we were using an old version of JSW to daemonize our service. What are the cool kids using these days?
The TaskServlet doesn't return a content type, which begs the question…what content type should the Tasks be writing to the PrintWriter? Tasks don't have any control over the Content-Type, indicating that dropwizard is in control of that. But there's no indication of what they ought to be sending back (text/plain? text/html? text/xml? application/json?).
From #109:
ERROR [2012-06-11 01:22:58,720] com.alpinefex.gcwizard.GCWizardResource: gcwizard error in sayHello
! javax.ws.rs.WebApplicationException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:103)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.readFrom(JacksonMessageBodyProvider.java:82)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:554)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
! at com.sun.jersey.api.client.WebResource.handle(WebResource.java:684)
! at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
! at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
! at com.alpinefex.gcwizard.GCWizardResource.dumpMetrics(GCWizardResource.java:84)
! at com.alpinefex.gcwizard.GCWizardResource.sayHello(GCWizardResource.java:72)
! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
! at java.lang.reflect.Method.invoke(Method.java:597)
! at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
! at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
! at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$TimedRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:34)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$ExceptionMeteredRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:73)
! at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
! at com.sun.jersey.server.impl.uri.rules.ResourceObjectRule.accept(ResourceObjectRule.java:100)
! at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
! at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
! at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
! at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
! at com.yammer.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:47)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1367)
! at com.yammer.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:29)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1338)
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:484)
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at com.yammer.metrics.jetty.InstrumentedHandler.handle(InstrumentedHandler.java:200)
! at org.eclipse.jetty.server.handler.GzipHandler.handle(GzipHandler.java:270)
! at com.yammer.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:123)
! at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at org.eclipse.jetty.server.Server.handle(Server.java:350)
! at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
! at org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:47)
! at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:890)
! at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:944)
! at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:630)
! at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:230)
! at org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:66)
! at org.eclipse.jetty.server.nio.BlockingChannelConnector$BlockingChannelEndPoint.run(BlockingChannelConnector.java:293)
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:603)
! at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:538)
! at java.lang.Thread.run(Thread.java:680)
Caused by: ! org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
! at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:219)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:44)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:13)
! at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2732)
! at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1923)
! at com.yammer.dropwizard.json.Json.readValue(Json.java:335)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:101)
!... 56 common frames omitted
ERROR [2012-06-11 01:22:58,722] com.yammer.dropwizard.jersey.LoggingExceptionMapper: Error handling a request: 46b4c2d7ea57bef0
! java.lang.RuntimeException: javax.ws.rs.WebApplicationException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at com.alpinefex.gcwizard.GCWizardResource.sayHello(GCWizardResource.java:76)
! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
! at java.lang.reflect.Method.invoke(Method.java:597)
! at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
! at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
! at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$TimedRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:34)
! at com.yammer.metrics.jersey.InstrumentedResourceMethodDispatchProvider$ExceptionMeteredRequestDispatcher.dispatch(InstrumentedResourceMethodDispatchProvider.java:73)
! at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
! at com.sun.jersey.server.impl.uri.rules.ResourceObjectRule.accept(ResourceObjectRule.java:100)
! at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
! at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
! at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
! at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
! at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
! at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
! at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
! at com.yammer.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:47)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1367)
! at com.yammer.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:29)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1338)
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:484)
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at com.yammer.metrics.jetty.InstrumentedHandler.handle(InstrumentedHandler.java:200)
! at org.eclipse.jetty.server.handler.GzipHandler.handle(GzipHandler.java:270)
! at com.yammer.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:123)
! at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
! at org.eclipse.jetty.server.Server.handle(Server.java:350)
! at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
! at org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:47)
! at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:890)
! at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:944)
! at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:630)
! at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:230)
! at org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:66)
! at org.eclipse.jetty.server.nio.BlockingChannelConnector$BlockingChannelEndPoint.run(BlockingChannelConnector.java:293)
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:603)
! at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:538)
! at java.lang.Thread.run(Thread.java:680)
Caused by: ! javax.ws.rs.WebApplicationException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:103)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.readFrom(JacksonMessageBodyProvider.java:82)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:554)
! at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
! at com.sun.jersey.api.client.WebResource.handle(WebResource.java:684)
! at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
! at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
! at com.alpinefex.gcwizard.GCWizardResource.dumpMetrics(GCWizardResource.java:84)
! at com.alpinefex.gcwizard.GCWizardResource.sayHello(GCWizardResource.java:72)
!... 48 common frames omitted
Caused by: ! org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: com.sun.jersey.client.apache4.ApacheHttpClient4Handler$HttpClientResponseInputStream@3c9ed91f; line: 1, column: 1]
! at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
! at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:219)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:44)
! at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:13)
! at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2732)
! at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1923)
! at com.yammer.dropwizard.json.Json.readValue(Json.java:335)
! at com.yammer.dropwizard.jersey.JacksonMessageBodyProvider.parseEntity(JacksonMessageBodyProvider.java:101)
!... 56 common frames omitted
We have a service our app connects to which is exposed via HTTPS. The cert contains the same host name for every environment (internally we use DNS switching to move between environments). In order to support connecting to this externally (where we don't control DNS) it would be great to have some config exposed that allows setting of name overrides by providing a DnsResolver to the apache http client.
I'm happy to write the code for this if it's likely to get merged.
It would be easier for people not using maven, to combine all jars in single dropwizard.jar, metrics.jar.
I noticed that two types, Size and Duration, are not by default serializable with Jackson. But it looks like 'toString()' method would work well, so the fix would be as simple as adding @JsonValue
for 'toString()' methods. I assume this is ok since there is already @JsonCreator
used; otherwise we could almost as easily create custom serializers, which is what I do locally.
My specific use case is debugging: I just want to print out Configuration object as JSON during startup.
Related to this, I guess it might be also useful to expose config object itself via GUI (similar to /threads etc); but I leave that for future improvements. :-)
(further ahead, really trying to dig into Jetty setup, JMX exposes only subset... but I digress).
Let me know if you want a patch (I realize that a unit test would be good, esp. for round-tripping); fix itself is trivial.
Supports Servlet 3.0, no other big changes.
Steal heavily from dogslow and log the stack traces of threads which have been running the same request for > N
ms.
We could use a hashed wheel timer for rough timeouts and then thread local ID counters -- when a request is handled, increment the thread's counter and schedule a job to execute in N
ms which checks that counter against the result of the increment. If the thread is still running but the counter hasn't been incremented, get its stack trace and log it.
There are scenarios in which getJerseyContainer will need to read the Service's com.yammer.dropwizard.config.Configuration but it has no way of accessing it.
The method signature can be changed to
public ServletContainer getJerseyContainer( DropwizardResourceConfig resourceConfig, T serviceConfig )
or DropwizardResourceConfig can be changed so that it has a publicly accessible reference to the service config.
The use-case is as follows:
When using Guice, a service will override getJerseyContainer to return com.sun.jersey.guice.spi.container.servlet.GuiceContainer, which needs an initialized Injector. Initializing the injector can depend on the service's Configuration object.
Looks like ConfiguredCommand assumes that all commands directly extend it; so trying to use an intermediate base class, like:
class MyCommmand extends ConfiguredCommand<MyConfig> { }
will fail with exception like:
Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at com.yammer.dropwizard.cli.ConfiguredCommand.getConfigurationClass(ConfiguredCommand.java:36)
at com.yammer.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:62)
at com.yammer.dropwizard.cli.Command.run(Command.java:113)
at com.yammer.dropwizard.AbstractService.run(AbstractService.java:178)
I suspect same is true for other generic types, but this is the one I bumped into.
A work-around is to keep intermediate classes parametric as well.
To fix this it should be possible to just go down inheritance hierarchy to find the place where generic information is passed; and although type aliasing can theoretically be problem (someone using intermediate classes with different number of parameters etc), in practice this should suffice.
(and if not, java-classmate project can solve this cleanly and completely -- but it'd be one more dependency, although can be shaded)
It seems that the upgrade of Jetty has changed the semantics of HttpServletRequest.getServletPath(), such that it's returning "/tasks" for all requests at the Tasks servlet. The method getPathInfo() seems to fit the bill:
"Returns any extra path information associated with the URL the client sent when it made this request. The extra path information follows the servlet path but precedes the query string and will start with a "/" character."
Pull request forthcoming.
It's getting drug in via jetty-servlets.
(Do we even need jetty-servlets?)
We'd find it really useful to be able to specify two config files at startup, one for defaults, one for environment-specific overrides.
Would you be interested in including this if we supply a patch?
Curious as to the appetite for supporting moustache templates.
A couple weeks back I had done some experimental work in dropwizard-views to play around with the idea, it wasn't too difficult to add/cleanup a couple interfaces and provide support for both freemarker or moustache. They both work off a JavaBean model so it was basically just making the ViewMessageBodyWriter a little more extensible.
I realize these two frameworks are pretty much at either end of the templating landscape goes (logic vs. logicless), but if there's interest, I can tidy things up.
Cheers.
Because so much of Dropwizard is glue code, the way in which things are created, configured, and wired together could use a bit more love.
GuiceContainer
or what have youConfigurationFactory
and JacksonMessageBodyProvider
ConfigurationFactory
needs to always reject unknown fields)MetricsRegistry
/HealthCheckRegistry
I might be doing something stupid here, if so, apologies, but I have this logging configured
logging:
level: DEBUG
loggers:
"net.amadan.sal.migration.MigrationResource": DEBUG
console:
enabled: true
threshold: INFO
file:
enabled: true
threshold: INFO
currentLogFilename: migration.log
archivedLogFilenamePattern: migration-%d.log.gz
archivedFileCount: 50
timeZone: UTC
and with that, nothing gets written to the log file. If I change file/threshold to DEBUG/ALL, I see file logging. Is that intentional?
We'd like to be able to
a) Enforce SSL for admin servlet requests in addition to basic auth
b) Be more selective about which admin features are protected at all
Being able to add a servlet filter to the admin handler would be adequate for this.
Happy to submit a patch for this if it's likely to be included.
Coda,
First of all I can't thank you (and Yammer) enough for releasing this. Best-of-breed REST stack, out-of-the-box metrics, etc. (I could go on and on...)
In an hour or so, I was able to migrate a bunch of our JAX-RS services to dropwizard and get all the metrics and health checks we really need... Truly awesome.
Anyway, is there a mailing list for users to interact? If not could you establish one (google groups, etc.)?
Thanks again, this is great.
Right now ServletHolder#handle
has a synchronized block in it.
That will eventually cause tears.
This limitation is required for servlets but filters can and will be mapped to the same URL.
Test input file yay.mustache
uses LF
while the expected string evaluates to CRLF
under windows hence AssertionError
:
Expected: is "Hello Stranger!\r\nWoo!\r\n\r\n"
got: "Hello Stranger!\nWoo!\n\n"
I think the String.format
should also use LF
i.e.
String.format("Hello Stranger!\nWoo!\n\n")
As @BradHouse said on the mailing list:
I reguarly launch services with Foreman and usually launch multiple instances at the same time. Each instance needs a different port.
A more serious issue is if you want to run a DW service on something like Heroku. You must bind on the port they define via the $PORT environment variable. If you cannot pass this on the CLI you cannot run on their service. System.getenv("PORT") also works, but there are no bind points in DW to alter a Configuration instance prior to Jetty start. Not surprising as the DW approach strongly favours immutable configuration.
I noticed a pull request get merged a couple weeks ago that adds SSL termination within Drop Wizard. One of the big advantages of performing termination within Jetty (rather than in a fronting proxy) is having direct access to information about the client certificate. It would be great to have an authentication mechanism that returns the DN (or part thereof) from a validated client certificate.
Certificate authentication is a fairly widespread requirement for APIs, especially ones running over HTTP(S). I'd be happy to take a stab at implementing this if I can get some guidance about where such an implementation would go. (I'm very new to Drop Wizard.)
jbrauer@werner:~/projects/dropwizard (master)$ cat /home/jbrauer/projects/dropwizard/dropwizard-core/target/surefire-reports/com.yammer.dropwizard.config.tests.ConfigurationFactoryTest.txt
-------------------------------------------------------------------------------
Test set: com.yammer.dropwizard.config.tests.ConfigurationFactoryTest
-------------------------------------------------------------------------------
Tests run: 3, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: -2,104,463.334 sec <<< FAILURE!
throwsAnExceptionOnInvalidFiles(com.yammer.dropwizard.config.tests.ConfigurationFactoryTest) Time elapsed: 0 sec <<< FAILURE!
java.lang.AssertionError:
Expected: a string ending with "factory-test-invalid.yml has the following errors:\n * name must match \"[\w]+[\s]+[\w]+\" (was Boop)"
got: "/home/jbrauer/projects/dropwizard/dropwizard-core/target/test-classes/factory-test-invalid.yml has the following errors:\n * name muss auf Ausdruck \"[\w]+[\s]+[\w]+\" passen (was Boop)"
at org.junit.Assert.assertThat(Assert.java:780)
at org.junit.Assert.assertThat(Assert.java:738)
at com.yammer.dropwizard.config.tests.ConfigurationFactoryTest.throwsAnExceptionOnInvalidFiles(ConfigurationFactoryTest.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.apache.maven.surefire.junitcore.ConfigurableParallelComputer$AsynchronousRunner$1.call(ConfigurableParallelComputer.java:186)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
jbrauer@werner:~/projects/dropwizard (master)$ cat /home/jbrauer/projects/dropwizard/dropwizard-core/target/surefire-reports/com.yammer.dropwizard.validation.tests.ValidatorTest.txt
-------------------------------------------------------------------------------
Test set: com.yammer.dropwizard.validation.tests.ValidatorTest
-------------------------------------------------------------------------------
Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: -2,104,463.747 sec <<< FAILURE!
returnsASetOfErrorsForAnObject(com.yammer.dropwizard.validation.tests.ValidatorTest) Time elapsed: 0.001 sec <<< FAILURE!
java.lang.AssertionError:
Expected: is <[notNull may not be null (was null), tooBig must be less than or equal to 30 (was 50)]>
got: <[notNull kann nicht null sein (was null), tooBig muss kleinergleich 30 sein (was 50)]>
at org.junit.Assert.assertThat(Assert.java:780)
at org.junit.Assert.assertThat(Assert.java:738)
at com.yammer.dropwizard.validation.tests.ValidatorTest.returnsASetOfErrorsForAnObject(ValidatorTest.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.apache.maven.surefire.junitcore.ConfigurableParallelComputer$AsynchronousRunner$1.call(ConfigurableParallelComputer.java:186)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
This is more a suggestion than a bug, but I've been using Logback for my logging, and was curious if this was on the horizon or worth switching to? It is positioned to be the successor to log4j, and as such, they even provide a pretty lengthy explanation on why you should switch.
Anyways, love the project, and I'm itching to use it at work.
Although it's good engineering to make a defensive copy of the byte array in a public getter, it's unnecessary in this case because AssetServlet.CachedAsset is a private class and the byte array is effectively immutable (no other access modifies it).
The performance gain could be significant when serving large images.
The servlet's doGet method can safely access the private array directly:
output.write(cachedAsset.resource);
Looks like
only works with string query parameters. It would be cool if you could do Optional<Integer>
for a query param and have dropwizard do the right magic.
Right now if you do Optional<Integer>
, everything works just fine, but when you do get() you get a string which is surprising given the template type.
Currently in ConfigurationFactory the system property prefix is set to "dw." and cannot be changed. I would very much like to be able to change this.
Would it be possible to add this feature? Would it be accepted?
Would be cool to have JDBI and SQL in the example project.
I would be happy to push the changes using an embedded H2 database if you like.
How about adding a class similar to this to dropwizard-testing for end to end integration testing?
public class ServiceIntegrationTest<T extends Service> {
private static Log LOG = Log.forClass(ServiceIntegrationTest.class);
protected Server server;
protected int port, adminPort;
/**
* @see com.yammer.dropwizard.cli.ServerCommand#run
*/
@BeforeMethod
public void setUp() throws Exception {
final Service service = createServiceInstance();
int[] openPorts = getPossiblyOpenPorts(2);
port = openPorts[0];
adminPort = openPorts[1];
File temporaryConfigFile = createTemporaryConfigFile(port, adminPort);
ConfigurationFactory<?> factory = ConfigurationFactory.forClass(
service.getConfigurationClass(), new Validator(), service.getJacksonModules());
Configuration configuration = (Configuration) factory.build(temporaryConfigFile);
Environment environment = new Environment(service, configuration);
service.initializeWithBundles(configuration, environment);
server = new ServerFactory(configuration.getHttpConfiguration(),
service.getName()).buildServer(environment);
LOG.info("Starting embedded Jetty with configuration {}", configuration.toString());
server.start();
}
@AfterMethod
public void tearDown() throws Exception {
LOG.info("Stopping embedded Jetty server");
server.stop();
server.join();
}
/**
* This method tries to find a set of open ports by creating a bunch of
* server sockets.
* <p/>
* Note: This procedure is susceptible to a race condition and some
* of the returned ports may be in use
*/
private int[] getPossiblyOpenPorts(int number) throws IOException {
ServerSocket[] serverSockets = new ServerSocket[number];
try {
int[] ports = new int[number];
for (int i = 0; i < number; i++) {
serverSockets[i] = new ServerSocket(0 /* bind to any open port */);
ports[i] = serverSockets[i].getLocalPort();
}
return ports;
} finally {
for (ServerSocket socket : serverSockets) {
socket.close();
}
}
}
public Service createServiceInstance() throws Exception {
return getServiceClass().newInstance();
}
public String createConfigurationAsYaml() throws IOException {
return Resources.toString(Resources.getResource("config/test-jetty-config.yml"), Charsets.UTF_8);
}
private File createTemporaryConfigFile(int port, int adminPort) throws IOException {
File temporaryConfig = File.createTempFile("dropwizard", ".yml");
temporaryConfig.deleteOnExit();
Files.write(createConfigurationAsYaml() + "\n" +
"http:\n" +
" port: " + port + "\n" +
" adminPort: " + adminPort + "\n",
temporaryConfig, Charsets.UTF_8);
return temporaryConfig;
}
/**
* @see com.yammer.dropwizard.AbstractService#getConfigurationClass
*/
@SuppressWarnings("unchecked")
public final Class<T> getServiceClass() {
Type t = getClass();
while (t instanceof Class<?>) {
t = ((Class<?>) t).getGenericSuperclass();
}
if (t instanceof ParameterizedType) {
for (Type param : ((ParameterizedType) t).getActualTypeArguments()) {
if (param instanceof Class<?>) {
final Class<?> cls = (Class<?>) param;
if (Service.class.isAssignableFrom(cls)) {
return (Class<T>) cls;
}
}
}
}
throw new IllegalStateException("Can not figure out Configuration type " +
"parameterization for " + getClass().getName());
}
}
Mostly for local development.
The document at http://dropwizard.codahale.com/manual/core/#logging
says "Dropwizard uses Log4j for its logging backend."
It appears to be false as the pom.xml and source code only references logback.
I'd like requests to / to be served by an AssetBundle (while still being able to set other sub-paths via @Path
). When I try to do this with:
addBundle(new AssetsBundle("/assets/", 0, "/"));
I get the following error:
Exception in thread "main" java.lang.IllegalArgumentException: duplicate key: /*
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:115)
at com.google.common.collect.RegularImmutableMap.<init>(RegularImmutableMap.java:72)
at com.google.common.collect.ImmutableMap$Builder.fromEntryList(ImmutableMap.java:245)
at com.google.common.collect.ImmutableMap$Builder.build(ImmutableMap.java:231)
at com.yammer.dropwizard.config.Environment.getServlets(Environment.java:353)
at com.yammer.dropwizard.config.ServerFactory.createHandler(ServerFactory.java:180)
at com.yammer.dropwizard.config.ServerFactory.buildServer(ServerFactory.java:81)
at com.yammer.dropwizard.cli.ServerCommand.run(ServerCommand.java:50)
at com.yammer.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:71)
at com.yammer.dropwizard.cli.Command.run(Command.java:113)
at com.yammer.dropwizard.AbstractService.run(AbstractService.java:178)
at com.jamesward.BarService.main(BarService.java:11)
Jetty has SPDY support, http://wiki.eclipse.org/Jetty/Feature/SPDY.
Please add spdy support, it shuold be similar to ssl support that is already included.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.