Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Dropwizard

2,989 views

Published on

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

Published in: Technology
  • 12 Signs From The Universe When You Are On The... ■■■ http://t.cn/AiuvUMl2
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Free Healing Soundscape - Just click "Play" to immerse yourself in a beautiful "Sound Bath" that clears negativity, awakens abundance, and brings miracles into your life! Listen for yourself right now. ♣♣♣ http://scamcb.com/manifmagic/pdf
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Dropwizard

  1. 1. Dropwizard Scott Leberknight 4/29/2016
  2. 2. “…a Java framework for developing ops- friendly, high-performance, RESTful web services…”
  3. 3. “…pulls together stable, mature libraries from the Java ecosystem into a simple, light- weight package that lets you focus on getting things done…”
  4. 4. “…out-of-the-box support for sophisticated configuration, application metrics, logging, operational tools…”
  5. 5. “…allowing you and your team to ship a production-quality web service in the shortest time possible”
  6. 6. Key Takeaways…
  7. 7. Simple to Build Simple to Deploy Simple to Monitor RESTful web services that are…
  8. 8. Main Components Jetty - Standalone web server Jackson - JSON processing Jersey (JAX-RS) - REST Metrics - Application metrics
  9. 9. Other components… Hibernate Validator - Validation Logback & SLF4J - Logging Liquibase - Database migrations JDBI or Hibernate - Database access
  10. 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
  11. 11. Dropwizard app 30,000 foot view
  12. 12. Configuration Application (Jetty server) Resources (Jersey) Data access (DAOs) POJOs reads registers access serialize/ deserialize JSON CRUD (fromYAML file) (using Jackson) components
  13. 13. basic workflow HTTP Request Incoming POJO Resource method Logic, data access, etc. Outgoing POJO(s) HTTP Response Deserialize JSON Serialize JSON CLIENT
  14. 14. The Players
  15. 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. 16. Lets’ build a simple RESTful service to control Nest thermostats…
  17. 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
  18. 18. Lombok example #1 @Getter @Setter @EqualsAndHashCode @ToString @RequiredArgsConstructor
 @AllArgsConstructor
 public class Person {
 private String firstName;
 private String lastName;
 private int age; } or use @Data {
  19. 19. Lombok example #2 @Data @Builder
 @NoArgsConstructor
 public class Person {
 private String firstName;
 private String lastName;
 private int age; }
  20. 20. Lombok example #3 val p = Person.builder()
 .firstName("Bob")
 .lastName("Smith")
 .age(36)
 .build(); local variable type inference
  21. 21. configuration class @Getter
 @Setter
 @ToString
 public class NestConfiguration extends Configuration {
 
 @JsonProperty("database")
 @Valid
 @NotNull
 private DataSourceFactory dataSourceFactory;
 
 }

  22. 22. config YAML database:
 driverClass: org.h2.Driver
 user: nest
 password: ${DEVIGNITION_DB_PWD:-DevIg$2016}
 url: jdbc:h2:tcp://localhost/~/db/nest
 validationQuery: "/* Nest DB Health Check */ SELECT 42"
 properties:
 hibernate.connection.charSet: UTF-8
 hibernate.dialect: org.hibernate.dialect.H2Dialect
 hibernate.format_sql: true
 hibernate.show_sql: false
 
 logging:
 level: INFO
 loggers:
 com.devignition: DEBUG
 org.hibernate.SQL: DEBUG

  23. 23. Application main() - starts app (Jetty server) initialize() - bundles, configuration options, etc. run() - register Jersey resources & more
  24. 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. 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}
  26. 26. Bundles Re-usable functionality Examples: - Database migrations bundle - Hibernate bundle
  27. 27. Migrations Bundle Liquibase (out of box) Add migrations bundle to application class
  28. 28. initialize - add a Bundle // in Application#initialize() bootstrap.addBundle(new MigrationsBundle<NestConfiguration>() {
 @Override
 public PooledDataSourceFactory getDataSourceFactory(NestConfiguration config) {
 return config.getDataSourceFactory();
 }
 });
  29. 29. Liquibase migration <databaseChangeLog> <changeSet id="001-create-nests-table" author="batman"> <createTable tableName="nests"> <column name="id" type="bigint" autoIncrement="true">
 <constraints primaryKey="true" nullable="false"/>
 </column> <column name="location" type="varchar(256)"> <constraints nullable="false" unique="true"/>
 </column>
 <column name="temperature" type="int">
 <constraints nullable="false"/>
 </column>
 <column name="mode" type="varchar(256)">
 <constraints nullable="false"/>
 </column> </createTable> </changeSet> </databaseChangeLog>
  30. 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. 31. Hibernate Bundle creates… - managed connection pool - database health check - managed & instrumented SessionFactory
  32. 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.
  33. 33. managed executor // Create a Dropwizard-managed executor service boolean useDaemon = true;
 ScheduledExecutorService executor = environment.lifecycle()
 .scheduledExecutorService("special-task-%d", useDaemon)
 .build();
 executor.scheduleAtFixedRate(this::performTask, 1L, 5L, TimeUnit.MINUTES);
  34. 34. Health Checks Runtime test of behavior, dependencies, etc. Health checks should lightly test service dependencies, e.g. databases, downstream services, etc.
  35. 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. 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
  37. 37. representation (POJO) @Data
 @Entity
 @Table(name = "nests")
 public class NestThermostat { @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id; 
 @NotBlank @Length(max = 256)
 private String location;
 
 @NotNull @Min(60) @Max(90)
 private Integer temperature;
 @NotNull
 @Enumerated(EnumType.STRING)
 private Mode mode; @JsonIgnore
 private UUID internalGuid;
 }
  38. 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. 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. 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. 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
  42. 42. resource class @Path("/nests")
 @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
 public class NestResource { private NestDao nestDao;
 
 public NestResource(NestDao nestDao) {
 this.nestDao = nestDao;
 } // resource methods (see next slide) } ( dependency injection w/o a framework…amazing what constructors can do ! )
  43. 43. example resource methods @GET
 @Path("/{id}")
 @Timed
 @ExceptionMetered
 @UnitOfWork
 public Optional<NestThermostat> getById(@PathParam("id") LongParam id) {
 return Optional.ofNullable(nestDao.getById(id.get()));
 }
 
 @POST
 @Timed
 @ExceptionMetered
 @UnitOfWork
 public Response addNest(@Valid NestThermostat nest) {
 long id = nestDao.create(nest);
 URI location = UriBuilder.fromResource(NestResource.class) .path("{id}").build(id);
 return Response.created(location)
 .entity(nest)
 .build();
 }
  44. 44. Now let's put on our DevOps hat… https://twitter.com/shu/status/575801992641056768
  45. 45. Fat JARs Maven Shade plugin Single executable "fat" JAR files One easily deployable artifact (*) (*) POJJ - Plain Old Java JAR
  46. 46. <plugin>
 <artifactId>maven-jar-plugin</artifactId>
 <version>2.6</version>
 <configuration>
 <archive>
 <manifest>
 <addClasspath>true</addClasspath>
 <mainClass>${mainClass}</mainClass>
 <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
 </manifest>
 </archive>
 </configuration>
 </plugin> Versioned JARs Add Implementation-Version to JAR manifest Maven jar plugin
  47. 47. Manifest-Version: 1.0 Implementation-Title: Nest Example Service Implementation-Version: 1.0.0 Archiver-Version: Plexus Archiver Built-By: sleberkn Implementation-Vendor-Id: com.devignition 3. MANIFEST.MF (in JAR) <groupId>com.devignition</groupId> <artifactId>nest-service</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>Nest Example Service</name> 1. pom.xml (in project) nest-service-1.0.0.jar 2. Build JAR file / maven-jar-plugin
  48. 48. Deployment steps Build executable fat JAR Run database migrations (if any) Start application (embedded Jetty server)
  49. 49. Build JAR $ mvn clean package (*) Chicken & egg - database tests will fail without first migrating
  50. 50. 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
  51. 51. Check, Migrate & Run! $ java -jar nest-service-1.0.0.jar check config.yml $ java -jar nest-service-1.0.0.jar db migrate config.yml $ java -jar nest-service-1.0.0.jar server config.yml
  52. 52. 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
  53. 53. Ping…
  54. 54. (HTTP) GET Our Nests
  55. 55. DevOps Menu
  56. 56. Check our health
  57. 57. Metrics (there are a LOT)
  58. 58. Console Metrics reporting Graphite CSV files Ganglia Custom…SLF4J
  59. 59. Monitoring
  60. 60. Common OS monitoring tools ps, top, htop, lsof, iostat, etc.
  61. 61. Common OS monitoring tools ps, top, htop, lsof, iostat, etc.
  62. 62. Testing Dropwizard Fixtures for unit testing representations Easily unit test resources using mock DAOs Excellent integration test support… Prefer AssertJ fluent-assertions
  63. 63. Lots of unit tests….
  64. 64. Integration testing ResourceTestRule DropwizardClientRule DropwizardAppRule DropwizardTestSupport
  65. 65. 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)
  66. 66. 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)
  67. 67. & more to explore… Tasks Authentication Filters Simple Views Form Handling Clients Polymorphic Config Logging HTTP/2 HTTPS/TLS
  68. 68. Wrap-up Production-focused, RESTful web services DevOps-friendly deployment & monitoring Make your apps Twelve-Factor apps…
  69. 69. The Twelve-Factor App Dropwizard apps have many characteristics of 12-Factor apps http://12factor.net
  70. 70. Simple to Build Simple to Deploy Simple to Monitor RESTful web services that are…
  71. 71. sample code available at: https://github.com/sleberknight/dropwizard-devignition-2016
  72. 72. https://jersey.java.net/ References, Act I http://www.dropwizard.io/ http://wiki.fasterxml.com/JacksonHome http://www.eclipse.org/jetty/ https://dropwizard.github.io/metrics/
  73. 73. References, Act II http://hibernate.org/validator/ http://www.jdbi.org/ http://www.liquibase.org/ http://www.joda.org/joda-time/ https://github.com/google/guava/wiki
  74. 74. 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/
  75. 75. My Info sleberknight at fortitudetec.com www.fortitudetec.com @sleberknight scott.leberknight at gmail
  76. 76. Dropwizard??? http://gunshowcomic.com/316

×