A while ago, I wrote about how to set up Guice, Jetty, Jersey, and Jackson and then how to calculate metrics about Jersey resource methods. We’ve subsequently open sourced some libraries to make it easy to use these (and other) techniques.
I’ll be describing each of our new libraries in turn, or you can skip to the end and look at a sample app to see them in action.
Jersey CORS Filter
CORS allows better cross-domain sharing of Web resources. jersey-cors-filter eases the task of adding CORS headers to Jersey resource methods. In the simple case, you can annotate a resource method with @Cors
and that’s all.
Having an @Cors
annotation on the method or class will result in Access-Control-Allow-Origin
and other CORS headers being set on the response:
@Path("foo") public class FooResource { @GET @Cors public String get() { return "some data"; } }
If you watch the log output in the sample app, you’ll see that the request that should get Access-Control-Allow-Origin
is displaying the value it receives for that header.
Jersey Metrics Filter
jersey-metrics-filter is a pre-packaged and improved version of the metrics-calculating technique described in an earlier blog post. In the default config, all Jersey resource methods will have timing and status code count metrics measured for them, but that can also be customized with the @ResourceMetrics
annotation.
This method would have timing measured, but status codes will not be tallied:
@GET @ResourceMetrics(statusCodeCounter = false, timer = true) public String get() { return "stuff"; }
The sample app uses Metrics’ JmxReporter to make all metrics available via JMX, so be sure to open up jconsole
to take a look.
Jersey Guice Dispatch Wrapper
jersey-guice-dispatch-wrapper is used by jersey-metrics-filter
to directly wrap the invocation of Jersey resource methods so that timing information can be captured accurately. Most filtering needs can be accomplished with Jersey’s ContainerRequestFilter
and ContainerResponseFilter
, but if you need javax.servlet.Filter
-style direct wrapping of request handling, this library will simplify the Jersey boilerplate.
Jetty HTTP Server Wrapper
jetty-http-server-wrapper provides a simple way to set up an embedded Jetty HTTP server with Guice Servlet. While you can certainly set up Jetty manually, this library lets you focus more on configuration rather than the mechanics of wiring up a ServletContextHolder
, etc. It also provides sane defaults for TLS ciphers and protocols.
Here’s a simple TLS HTTP server:
KeyStore keyStore = getServerKeystoreFromSomewhere(); HttpServerConnectorConfig httpsConfig = HttpServerConnectorConfig.forHttps("localhost", 8443) .withTlsKeystore(keyStore) .withTlsKeystorePassphrase("password"); httpServerFactory .getHttpServerWrapper(new HttpServerWrapperConfig().withHttpServerConnectorConfig(httpsConfig)) .start();
URL Builder
url-builder provides a builder-style API for assembling correctly-encoded URLs. See this blog post for more details on why this isn’t easily done using the built-in Java libraries. A simple example:
UrlBuilder.forHost("http", "localhost", 8080) .pathSegment("foo") .queryParam("search", "some stuff") .toUrlString();
Jersey/New Relic Integration
jersey-new-relic lets Jersey resource requests have useful New Relic transaction names that include the value of the appropriate @Path
annotations. Without this, all Jersey requests show up as being handled by ServletContainer
(or GuiceContainer
if you’re using Guice). It also informs New Relic of exceptions thrown during request processing.
Demo app
I’ve put together a runnable sample app that shows all of these libraries in use. Grab the code, execute gradle run
, and open up jconsole
to look at the generated metrics. If you have New Relic, follow the instructions in the README to have data recorded in New Relic as well.
It happens to be written in Groovy, but is easily translatable to Java. We use this style of service (embedded Jetty with simple main()
-method startup) for all of our Java web services that do not have to be deployed as a .war
for compatibility with existing systems.
We’ve still got a few more things to release, but this is enough to get a useful service up and running. Let us know in the comments if you have suggestions for how any of these can be improved.