Slides accompanying a presentation on Dropwizard I gave at the DevIgnition conference ( www.devignition.com ) on April 29, 2016. The sample code is on GitHub at https://github.com/sleberknight/dropwizard-devignition-2016
10. And more…
Google Guava - Utilities
HttpClient or Jersey Client - HTTP clients
Joda Time - Date/time API
(*)
(*) Java 8 Date/Time API supersedes Joda
Freemarker & Mustache - Views/templates
15. Class/Component Description
Configuration
Application configuration de-serialized fromYAML file
(via Jackson-annotated class)
Application
Initialize bundles, commands, resources, health checks,
etc. Starts Jetty server.
Resource Annotated Jersey/JAX-RS classes
DAO
Data access layer. Native Hibernate (AbstractDAO) and
JDBI support.
HealthCheck
Defines a runtime test of application behavior,
dependencies, etc.
Managed Objects Components requiring an explicit lifecycle (start / stop)
Command
Define command line actions (e.g. server starts Jetty; db
handles database operations)
POJOs (aka Representations)
Objects representing a service's RESTful API, serialized/
deserialized by Jackson
16. Lets’ build a simple
RESTful service to
control Nest thermostats…
17. Quick Digression - Lombok
“Project Lombok makes java a spicier
language by adding ‘handlers’ that know
how to build and compile simple,
boilerplate-free, not-quite-java code.”
- projectlombok.org
23. Application
main() - starts app (Jetty server)
initialize() - bundles, configuration options, etc.
run() - register Jersey resources & more
24. application class
public class NestApplication
extends Application<NestConfiguration> {
public static void main(final String[] args) throws Exception {
new NestApplication().run(args);
}
@Override public String getName() { return “Nest Service"; }
@Override
public void initialize(Bootstrap<NestConfiguration> bootstrap) {
// initialize bundles, e.g. migrations, Hibernate, etc.
}
@Override
public void run(NestConfiguration configuration,
Environment environment) {
// register resources, health checks, metrics, etc.
}
}
25. initialize - env var substitution
// in Application#initialize()
bootstrap.setConfigurationSourceProvider(
new SubstitutingSourceProvider(
bootstrap.getConfigurationSourceProvider(),
new EnvironmentVariableSubstitutor(false)));
# config.yml
# Use DEVIGNITION_DB_PWD env var, or
# default to DevIg$2016 if not exists (bash syntax)
password: ${DEVIGNITION_DB_PWD:-DevIg$2016}
30. run - register a resource
@Override
public void run(NestConfiguration configuration,
Environment environment) {
NestDao nestDao = new NestDao(
hibernateBundle.getSessionFactory());
NestResource nestResource = new NestResource(nestDao);
environment.jersey().register(nestResource);
}
31. Hibernate Bundle creates…
- managed connection pool
- database health check
- managed & instrumented SessionFactory
32. Managed Objects
Objects that are tied to the application’s
lifecycle (i.e. to Jetty lifecycle)
start() called before server starts
stop() called after server shuts down
Ideal for thread pools, scheduled executors, etc.
34. Health Checks
Runtime test of behavior, dependencies, etc.
Health checks should lightly test service
dependencies, e.g. databases, downstream
services, etc.
35. health check
public class NestServiceHealthCheck extends HealthCheck {
private NestService nestService;
public NestServiceHealthCheck(NestService service) {
this.nestService = service;
}
@Override
protected Result check() throws Exception {
NestServiceStatus status = nestService.currentStatus();
if (status.ok() {
return Result.healthy();
} else {
return Result.unhealthy(status.problems());
}
}
}
36. Representations
Generally…just POJOs
Use Hibernate Validator, e.g. @NotBlank
Optionally use advanced Jackson features,
e.g. custom serializers or deserializers
Sprinkle in Jackson annotations, e.g. @JsonIgnore
38. Data Access / Application Logic
Use whatever makes sense for a given service
Difference services may use different data stores
- Postgres for relational data
- Neo4J for connected data
- MongoDB for document-oriented data
39. DAO (Hibernate)
public class NestDao extends AbstractDAO<NestThermostat> {
public NestDao(SessionFactory sessionFactory) { super(sessionFactory); }
public NestThermostat getById(long id) { return get(id); }
public List<NestThermostat> getAll() {
Criteria criteria = currentSession().createCriteria(getEntityClass())
.addOrder(Order.asc("location"));
return list(criteria);
}
public long create(NestThermostat nest) {
checkState(nest.getId() == null, "New nests cannot have an id");
return persist(nest).getId();
}
public void update(NestThermostat nest) {
checkState(nest.getId() != null, "Existing Nest must have an id");
persist(nest);
}
public void delete(long id) { currentSession().delete(getById(id)); }
}
40. DAO (JDBI)
public interface NestDao {
@SqlQuery("select * from nests order by location")
@Mapper(NestMapper.class)
ImmutableList<Nest> getAllNests();
@SqlQuery("select * from nests where location = :it")
@Mapper(NestMapper.class)
@SingleValueResult(Nest.class)
Optional<Nest> getNest(@Bind String location);
@GetGeneratedKeys
@SqlUpdate("insert into nests (location, location_id)"
+ " values (:location, :locationId)")
long createNest(@BindBean Nest nest);
@SqlUpdate("delete from nests where location = :it")
void deleteNest(@Bind String location);
}
41. Resource classes
Mostly just Jersey (JAX-RS) resource classes
Dropwizard adds some additional features, e.g.
- validation with @Valid
- AbstractParam and implementations
- Metrics support, e.g. @Timed
50. Build JAR
$ mvn clean package
(*) Chicken & egg - database tests will fail without first migrating
51.
52. Commands
$ java -jar nest-service-1.0.0.jar
usage: java -jar nest-service-1.0.0.jar
[-h] [-v] {server,check,db} ...
positional arguments:
{server,check,db} available commands
optional arguments:
-h, --help show this help message and exit
-v, --version show the application version and exit
54. Jetty is now listening…
Dropwizard App
(Jetty)
App Port
8080
Admin Port
8081
GET my.nest.com:8080 /nests
GET my.nest.com:8081 /healthcheck
GET my.nest.com:8081 /metrics
GET my.nest.com:8081 /ping
GET my.nest.com:8081 /threads
GET my.nest.com:8080 /nests/2
64. Testing Dropwizard
Fixtures for unit testing representations
Easily unit test resources using mock DAOs
Excellent integration test support…
Prefer AssertJ fluent-assertions
67. ResourceTestRule
public class NestResourceIntegrationTest {
private static final NestDao NEST_DAO = mock(NestDao.class);
@ClassRule
public static final ResourceTestRule RESOURCE = ResourceTestRule.builder()
.addResource(new NestResource(NEST_DAO))
.build();
@After public void tearDown() { reset(NEST_DAO); }
@Test
public void testGetNestById() {
long id = 42;
NestThermostat nest = newNest(id, "Kitchen", 72, Mode.COOL);
when(NEST_DAO.getById(id)).thenReturn(nest);
assertThat(RESOURCE.client()
.target("/nests/42")
.request()
.get(NestThermostat.class))
.isEqualToComparingFieldByField(nest);
}
}
(in-memory Jersey server)
68. DropwizardAppRule
public class NestApplicationIntegrationTest {
@ClassRule
public static final DropwizardAppRule<NestConfiguration> APP =
new DropwizardAppRule<>(NestApplication.class,
ResourceHelpers.resourceFilePath("test-app-config.yml"));
@Test
public void testGetNest() {
Client client = new JerseyClientBuilder(APP.getEnvironment())
.build("app test client");
String url = String.format("http://localhost:%d/nests",
APP.getLocalPort());
Response response = client.target(url)
.request()
.get();
assertThat(response.getStatusInfo()).isEqualTo(Response.Status.OK);
}
}
(full integration test starts your entire app)
69. & more to explore…
Tasks
Authentication
Filters
Simple Views
Form Handling
Clients
Polymorphic Config
Logging HTTP/2
HTTPS/TLS
76. Photo Attributions
nest thermostat - http://www.nest.com
bundle - https://www.flickr.com/photos/pembo1781/5477885038/
caduceus - https://www.flickr.com/photos/26672416@N00/4777701981/
DevOps hat - https://twitter.com/shu/status/575801992641056768
coffee in mason jar - https://www.flickr.com/photos/traveloriented/9757236883/
tux - http://powerpcaccess.blogspot.com/2013/03/linux-
on-ppc-mac.html#.VyGHCBMrLdQ
(I own or took all other photos myself)
gunshow comic - http://gunshowcomic.com/316
half moon - https://www.flickr.com/photos/75929731@N08/7044973631/