Browse Source

Merge pull request #850 from reines/dropwizard_updates

Dropwizard updates
mcocciaTE 11 years ago
parent
commit
18874ed160

+ 3 - 0
dropwizard/benchmark_config

@@ -6,6 +6,9 @@
       "json_url": "/json",
       "json_url": "/json",
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/db?queries=",
       "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/db/update?queries=",
+      "plaintext_url": "/plaintext",
       "port": 9000,
       "port": 9000,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Fullstack",
       "classification": "Fullstack",

+ 10 - 26
dropwizard/hello-world.yml

@@ -1,12 +1,16 @@
-http:
-  port: 9000
+server:
+  type: simple
+  applicationContextPath: /
+  connector:
+    type: http
+    port: 9000
+    useServerHeader: true
 
 
   requestLog:
   requestLog:
+    appenders: []
 
 
-    # Settings for logging to stdout.
-    console:
-      # If true, log requests to stdout.
-      enabled: false
+logging:
+  appenders: []
 
 
 database:
 database:
   # the name of your JDBC driver
   # the name of your JDBC driver
@@ -28,9 +32,6 @@ database:
   # the maximum amount of time to wait on an empty pool before throwing an exception
   # the maximum amount of time to wait on an empty pool before throwing an exception
   maxWaitForConnection: 1s
   maxWaitForConnection: 1s
 
 
-  # the SQL query to run when validating a connection's liveness
-  validationQuery: "/* MyService Health Check */ SELECT 1"
-
   # the minimum number of connections to keep open
   # the minimum number of connections to keep open
   minSize: 8
   minSize: 8
 
 
@@ -39,20 +40,3 @@ database:
 
 
   # whether or not idle connections should be validated
   # whether or not idle connections should be validated
   checkConnectionWhileIdle: false
   checkConnectionWhileIdle: false
-
-  # how long a connection must be held before it can be validated
-  checkConnectionHealthWhenIdleFor: 10s
-
-  # the maximum lifetime of an idle connection
-  closeConnectionIfIdleFor: 1 minute
-
-logging:
-
-  # The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
-  level: OFF
-
-  console:
-
-    # If true, write log statements to stdout.
-    enabled: false
-

+ 20 - 10
dropwizard/pom.xml

@@ -1,28 +1,38 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
 
 
     <groupId>com.xekm</groupId>
     <groupId>com.xekm</groupId>
     <artifactId>hello-world</artifactId>
     <artifactId>hello-world</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <version>0.0.1-SNAPSHOT</version>
 
 
+    <properties>
+        <jdk.version>1.7</jdk.version>
+
+        <dropwizard.version>0.7.0</dropwizard.version>
+        <mysql-connector-java.version>5.1.30</mysql-connector-java.version>
+    </properties>
+
     <dependencies>
     <dependencies>
         <dependency>
         <dependency>
-            <groupId>com.yammer.dropwizard</groupId>
+            <groupId>io.dropwizard</groupId>
             <artifactId>dropwizard-core</artifactId>
             <artifactId>dropwizard-core</artifactId>
-            <version>0.6.2</version>
+            <version>${dropwizard.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
-            <groupId>com.yammer.dropwizard</groupId>
+            <groupId>io.dropwizard</groupId>
             <artifactId>dropwizard-hibernate</artifactId>
             <artifactId>dropwizard-hibernate</artifactId>
-            <version>0.6.2</version>
+            <version>${dropwizard.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-views-mustache</artifactId>
+            <version>${dropwizard.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>mysql</groupId>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <artifactId>mysql-connector-java</artifactId>
-            <version>5.1.6</version>
+            <version>${mysql-connector-java.version}</version>
         </dependency>
         </dependency>
     </dependencies>
     </dependencies>
 
 
@@ -33,8 +43,8 @@
                 <artifactId>maven-compiler-plugin</artifactId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>2.3.2</version>
                 <version>2.3.2</version>
                 <configuration>
                 <configuration>
-                    <source>1.7</source>
-                    <target>1.7</target>
+                    <source>${jdk.version}</source>
+                    <target>${jdk.version}</target>
                 </configuration>
                 </configuration>
             </plugin>
             </plugin>
             <plugin>
             <plugin>

+ 14 - 10
dropwizard/setup.py

@@ -1,25 +1,29 @@
 import subprocess
 import subprocess
-import sys
 import setup_util
 import setup_util
 from os.path import expanduser
 from os.path import expanduser
 import os
 import os
 
 
 home = expanduser("~")
 home = expanduser("~")
 
 
+
 def start(args, logfile, errfile):
 def start(args, logfile, errfile):
-    setup_util.replace_text("dropwizard/hello-world.yml", "url: jdbc:mysql://.*/hello_world", "url: jdbc:mysql://" + args.database_host + ":3306/hello_world")
+    setup_util.replace_text("dropwizard/hello-world.yml", "url: jdbc:mysql://.*/hello_world",
+                            "url: jdbc:mysql://" + args.database_host + ":3306/hello_world")
 
 
     try:
     try:
         subprocess.check_call("mvn clean package;", shell=True, cwd="dropwizard", stderr=errfile, stdout=logfile)
         subprocess.check_call("mvn clean package;", shell=True, cwd="dropwizard", stderr=errfile, stdout=logfile)
-        subprocess.Popen("java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml", shell=True, cwd="dropwizard", stderr=errfile, stdout=logfile)
+        subprocess.Popen("java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml", shell=True,
+                         cwd="dropwizard", stderr=errfile, stdout=logfile)
         return 0
         return 0
     except subprocess.CalledProcessError:
     except subprocess.CalledProcessError:
         return 1
         return 1
+
+
 def stop(logfile, errfile):
 def stop(logfile, errfile):
-  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
-  out, err = p.communicate()
-  for line in out.splitlines():
-    if 'hello-world' in line:
-      pid = int(line.split(None, 2)[1])
-      os.kill(pid, 15)
-  return 0
+    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+    out, err = p.communicate()
+    for line in out.splitlines():
+        if 'hello-world' in line:
+            pid = int(line.split(None, 2)[1])
+            os.kill(pid, 15)
+    return 0

+ 15 - 5
dropwizard/source_code

@@ -1,10 +1,20 @@
 ./dropwizard/src/main/java/com/example/helloworld/
 ./dropwizard/src/main/java/com/example/helloworld/
+./dropwizard/src/main/java/com/example/helloworld/config
+./dropwizard/src/main/java/com/example/helloworld/config/HelloWorldConfiguration
 ./dropwizard/src/main/java/com/example/helloworld/db
 ./dropwizard/src/main/java/com/example/helloworld/db
+./dropwizard/src/main/java/com/example/helloworld/db/model
+./dropwizard/src/main/java/com/example/helloworld/db/model/Fortune
+./dropwizard/src/main/java/com/example/helloworld/db/model/World
+./dropwizard/src/main/java/com/example/helloworld/db/FortuneDAO.java
 ./dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java
 ./dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java
-./dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
 ./dropwizard/src/main/java/com/example/helloworld/resources
 ./dropwizard/src/main/java/com/example/helloworld/resources
-./dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
+./dropwizard/src/main/java/com/example/helloworld/resources/api
+./dropwizard/src/main/java/com/example/helloworld/resources/api/HelloMessage
+./dropwizard/src/main/java/com/example/helloworld/resources/views
+./dropwizard/src/main/java/com/example/helloworld/resources/views/FortuneView
+./dropwizard/src/main/java/com/example/helloworld/resources/FortuneResource.java
 ./dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java
 ./dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java
-./dropwizard/src/main/java/com/example/helloworld/core
-./dropwizard/src/main/java/com/example/helloworld/core/World.java
-./dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java
+./dropwizard/src/main/java/com/example/helloworld/resources/TextResource.java
+./dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
+./dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
+./dropwizard/src/main/resources/fortunes.mustache

+ 0 - 25
dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java

@@ -1,25 +0,0 @@
-
-package com.example.helloworld;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-
-import org.hibernate.validator.constraints.NotEmpty;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.yammer.dropwizard.config.Configuration;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
-
-public class HelloWorldConfiguration
-    extends Configuration
-{
-  @Valid
-  @NotNull
-  @JsonProperty
-  private DatabaseConfiguration database    = new DatabaseConfiguration();
-
-  public DatabaseConfiguration getDatabaseConfiguration()
-  {
-    return database;
-  }
-}

+ 34 - 37
dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java

@@ -1,48 +1,45 @@
-
 package com.example.helloworld;
 package com.example.helloworld;
 
 
-import com.example.helloworld.core.World;
+import com.example.helloworld.config.HelloWorldConfiguration;
+import com.example.helloworld.db.FortuneDAO;
+import com.example.helloworld.db.model.Fortune;
+import com.example.helloworld.db.model.World;
 import com.example.helloworld.db.WorldDAO;
 import com.example.helloworld.db.WorldDAO;
+import com.example.helloworld.resources.FortuneResource;
 import com.example.helloworld.resources.JsonResource;
 import com.example.helloworld.resources.JsonResource;
+import com.example.helloworld.resources.TextResource;
 import com.example.helloworld.resources.WorldResource;
 import com.example.helloworld.resources.WorldResource;
-import com.yammer.dropwizard.Service;
-import com.yammer.dropwizard.config.Bootstrap;
-import com.yammer.dropwizard.config.Environment;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
-import com.yammer.dropwizard.hibernate.HibernateBundle;
+import io.dropwizard.Application;
+import io.dropwizard.db.DataSourceFactory;
+import io.dropwizard.hibernate.HibernateBundle;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+import io.dropwizard.views.ViewBundle;
 
 
-public class HelloWorldService
-    extends Service<HelloWorldConfiguration>
-{
-  private final HibernateBundle<HelloWorldConfiguration> hibernate = new HibernateBundle<HelloWorldConfiguration>(
-                                                                       World.class)
-                                                                   {
-                                                                     @Override
-                                                                     public DatabaseConfiguration getDatabaseConfiguration(
-                                                                         HelloWorldConfiguration configuration)
-                                                                     {
-                                                                       return configuration.getDatabaseConfiguration();
-                                                                     }
-                                                                   };
+public class HelloWorldService extends Application<HelloWorldConfiguration> {
 
 
-  public static void main(String[] args) throws Exception
-  {
-    new HelloWorldService().run(args);
-  }
+    private final HibernateBundle<HelloWorldConfiguration> hibernate = new HibernateBundle<HelloWorldConfiguration>(World.class, Fortune.class) {
+        @Override
+        public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
+            return configuration.getDatabaseConfiguration();
+        }
+    };
 
 
-  @Override
-  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap)
-  {
-    bootstrap.setName("hello-world");
-    bootstrap.addBundle(hibernate);
-  }
+    public static void main(String[] args) throws Exception {
+        new HelloWorldService().run(args);
+    }
 
 
-  @Override
-  public void run(HelloWorldConfiguration config, Environment environment)
-  {
-    final WorldDAO dao = new WorldDAO(hibernate.getSessionFactory());
-    environment.addResource(new WorldResource(dao));
-    environment.addResource(new JsonResource());
-  }
+    @Override
+    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
+        bootstrap.addBundle(hibernate);
+        bootstrap.addBundle(new ViewBundle());
+    }
 
 
+    @Override
+    public void run(HelloWorldConfiguration config, Environment environment) {
+        environment.jersey().register(new JsonResource()); // Test type 1: JSON serialization
+        environment.jersey().register(new WorldResource(new WorldDAO(hibernate.getSessionFactory()))); // Test types 2, 3 & 5: Single database query, Multiple database queries & Database updates
+        environment.jersey().register(new FortuneResource(new FortuneDAO(hibernate.getSessionFactory()))); // Test type 4: Fortunes
+        environment.jersey().register(new TextResource()); // Test type 6: Plaintext
+    }
 }
 }

+ 20 - 0
dropwizard/src/main/java/com/example/helloworld/config/HelloWorldConfiguration.java

@@ -0,0 +1,20 @@
+package com.example.helloworld.config;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.dropwizard.Configuration;
+import io.dropwizard.db.DataSourceFactory;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+public class HelloWorldConfiguration extends Configuration {
+
+    @Valid
+    @NotNull
+    @JsonProperty
+    private DataSourceFactory database = new DataSourceFactory();
+
+    public DataSourceFactory getDatabaseConfiguration() {
+        return database;
+    }
+}

+ 0 - 36
dropwizard/src/main/java/com/example/helloworld/core/World.java

@@ -1,36 +0,0 @@
-
-package com.example.helloworld.core;
-
-import javax.persistence.*;
-
-@Entity
-@Table(name = "World")
-public class World
-{
-  @Id
-  @GeneratedValue(strategy = GenerationType.AUTO)
-  private long id;
-
-  @Column(name = "randomNumber", nullable = false)
-  private long randomNumber;
-
-  public long getId()
-  {
-    return id;
-  }
-
-  public void setId(long id)
-  {
-    this.id = id;
-  }
-
-  public long getRandomNumber()
-  {
-    return this.randomNumber;
-  }
-
-  public void setRandomNumber(long randomNumber)
-  {
-    this.randomNumber = randomNumber;
-  }
-}

+ 18 - 0
dropwizard/src/main/java/com/example/helloworld/db/FortuneDAO.java

@@ -0,0 +1,18 @@
+package com.example.helloworld.db;
+
+import com.example.helloworld.db.model.Fortune;
+import io.dropwizard.hibernate.AbstractDAO;
+import org.hibernate.SessionFactory;
+
+import java.util.List;
+
+public class FortuneDAO extends AbstractDAO<Fortune> {
+
+    public FortuneDAO(SessionFactory factory) {
+        super(factory);
+    }
+
+    public List<Fortune> list() {
+        return list(criteria());
+    }
+}

+ 14 - 15
dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java

@@ -1,22 +1,21 @@
-
 package com.example.helloworld.db;
 package com.example.helloworld.db;
 
 
+import com.example.helloworld.db.model.World;
+import com.google.common.base.Optional;
+import io.dropwizard.hibernate.AbstractDAO;
 import org.hibernate.SessionFactory;
 import org.hibernate.SessionFactory;
 
 
-import com.example.helloworld.core.World;
-import com.google.common.base.Optional;
-import com.yammer.dropwizard.hibernate.AbstractDAO;
+public class WorldDAO extends AbstractDAO<World> {
+
+    public WorldDAO(SessionFactory factory) {
+        super(factory);
+    }
 
 
-public class WorldDAO
-    extends AbstractDAO<World>
-{
-  public WorldDAO(SessionFactory factory)
-  {
-    super(factory);
-  }
+    public Optional<World> findById(Long id) {
+        return Optional.fromNullable(get(id));
+    }
 
 
-  public Optional<World> findById(Long id)
-  {
-    return Optional.fromNullable(get(id));
-  }
+    public World update(World world) {
+        return persist(world);
+    }
 }
 }

+ 35 - 0
dropwizard/src/main/java/com/example/helloworld/db/model/Fortune.java

@@ -0,0 +1,35 @@
+package com.example.helloworld.db.model;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "Fortune")
+public class Fortune implements Comparable<Fortune> {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private long id;
+
+    @Column(name = "message", nullable = false)
+    private String message;
+
+    @SuppressWarnings("unused")
+    public Fortune() {}
+
+    public Fortune(String message) {
+        this.message = message;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    @Override
+    public int compareTo(Fortune o) {
+        return message.compareTo(o.message);
+    }
+}

+ 29 - 0
dropwizard/src/main/java/com/example/helloworld/db/model/World.java

@@ -0,0 +1,29 @@
+package com.example.helloworld.db.model;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "World")
+public class World {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private long id;
+
+    @Column(name = "randomNumber", nullable = false)
+    private long randomNumber;
+
+    public World() {}
+
+    public long getId() {
+        return id;
+    }
+
+    public long getRandomNumber() {
+        return randomNumber;
+    }
+
+    public void setRandomNumber(long randomNumber) {
+        this.randomNumber = randomNumber;
+    }
+}

+ 37 - 0
dropwizard/src/main/java/com/example/helloworld/resources/FortuneResource.java

@@ -0,0 +1,37 @@
+package com.example.helloworld.resources;
+
+import com.example.helloworld.db.FortuneDAO;
+import com.example.helloworld.db.model.Fortune;
+import com.example.helloworld.resources.views.FortuneView;
+import com.google.common.collect.Lists;
+import io.dropwizard.hibernate.UnitOfWork;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.Collections;
+import java.util.List;
+
+@Path("/fortunes")
+@Produces(MediaType.TEXT_HTML + ";charset=UTF-8")
+public class FortuneResource {
+
+    private final FortuneDAO fortuneDAO;
+
+    public FortuneResource(FortuneDAO fortuneDAO) {
+        this.fortuneDAO = fortuneDAO;
+    }
+
+    @GET
+    @UnitOfWork
+    public FortuneView dbTest() {
+        final List<Fortune> fortunes = Lists.newArrayListWithExpectedSize(32);
+
+        fortunes.addAll(fortuneDAO.list());
+        fortunes.add(new Fortune("Additional fortune added at request time."));
+
+        Collections.sort(fortunes);
+        return new FortuneView(fortunes);
+    }
+}

+ 6 - 18
dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java

@@ -1,8 +1,6 @@
-
 package com.example.helloworld.resources;
 package com.example.helloworld.resources;
 
 
-import java.util.HashMap;
-import java.util.Map;
+import com.example.helloworld.resources.api.HelloMessage;
 
 
 import javax.ws.rs.GET;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Path;
@@ -11,20 +9,10 @@ import javax.ws.rs.core.MediaType;
 
 
 @Path("/json")
 @Path("/json")
 @Produces(MediaType.APPLICATION_JSON)
 @Produces(MediaType.APPLICATION_JSON)
-public class JsonResource
-{
-  // Response message class (copied from 'servlet' test)
-  public final static class HelloMessage {
-    public final String message;
-
-    public HelloMessage(String m) { message = m; }
-  }
-
-  public JsonResource() { }
+public class JsonResource {
 
 
-  @GET
-  public HelloMessage sayHello()
-  {
-    return new HelloMessage("Hello, World!");
-  }
+    @GET
+    public HelloMessage sayHello() {
+        return new HelloMessage("Hello, World!");
+    }
 }
 }

+ 16 - 0
dropwizard/src/main/java/com/example/helloworld/resources/TextResource.java

@@ -0,0 +1,16 @@
+package com.example.helloworld.resources;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/plaintext")
+@Produces(MediaType.TEXT_PLAIN)
+public class TextResource {
+
+    @GET
+    public String sayHello() {
+        return "Hello, World!";
+    }
+}

+ 47 - 28
dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java

@@ -1,41 +1,60 @@
 package com.example.helloworld.resources;
 package com.example.helloworld.resources;
 
 
-import java.util.Random;
+import com.example.helloworld.db.WorldDAO;
+import com.example.helloworld.db.model.World;
+import com.google.common.base.Optional;
+import io.dropwizard.hibernate.UnitOfWork;
 
 
 import javax.ws.rs.GET;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MediaType;
-
-import com.example.helloworld.core.World;
-import com.example.helloworld.db.WorldDAO;
-import com.google.common.base.Optional;
-import com.yammer.dropwizard.hibernate.UnitOfWork;
+import java.util.Random;
 
 
 @Path("/db")
 @Path("/db")
 @Produces(MediaType.APPLICATION_JSON)
 @Produces(MediaType.APPLICATION_JSON)
-public class WorldResource
-{
-  private WorldDAO worldDAO = null;
-
-  public WorldResource(WorldDAO worldDAO)
-  {
-    this.worldDAO = worldDAO;
-  }
-
-  @GET
-  @UnitOfWork
-  public World[] dbTest(@QueryParam("queries") Optional<Integer> queries)
-  {
-    final int totalQueries = queries.or(1);
-    final World[] worlds = new World[queries.or(1)];
-    final Random random = new Random(System.currentTimeMillis());
-
-    for (int i = 0; i < totalQueries; i++)
-    {
-      worlds[i] = this.worldDAO.findById((long)(random.nextInt(10000) + 1)).orNull();
+public class WorldResource {
+
+    private static final Random RANDOM = new Random();
+
+    private final WorldDAO worldDAO;
+
+    public WorldResource(WorldDAO worldDAO) {
+        this.worldDAO = worldDAO;
+    }
+
+    @GET
+    @UnitOfWork
+    public World[] dbTest(@QueryParam("queries") Optional<Integer> queries) {
+        final int totalQueries = queries.or(1); // TODO: Should be bound [1,500]
+        final World[] worlds = new World[totalQueries];
+
+        // TODO: Is parallelising this cheating?
+        for (int i = 0; i < totalQueries; i++) {
+            final long worldId = RANDOM.nextInt(10_000) + 1;
+            worlds[i] = worldDAO.findById(worldId).orNull();
+        }
+
+        return worlds;
+    }
+
+    @GET
+    @Path("/update")
+    @UnitOfWork
+    public World[] updateTest(@QueryParam("queries") Optional<Integer> queries) {
+        final int totalQueries = queries.or(1); // TODO: Should be bound [1,500]
+        final World[] worlds = new World[totalQueries];
+
+        // TODO: Is parallelising this cheating?
+        for (int i = 0; i < totalQueries; i++) {
+            final long worldId = RANDOM.nextInt(10_000) + 1;
+
+            final World world = worldDAO.findById(worldId).orNull();
+            world.setRandomNumber(RANDOM.nextInt(10_000) + 1);
+            worlds[i] = worldDAO.update(world);
+        }
+
+        return worlds;
     }
     }
-    return worlds;
-  }
 }
 }

+ 17 - 0
dropwizard/src/main/java/com/example/helloworld/resources/api/HelloMessage.java

@@ -0,0 +1,17 @@
+package com.example.helloworld.resources.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public final class HelloMessage {
+
+    @JsonProperty
+    private final String message;
+
+    public HelloMessage(String m) {
+        message = m;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

+ 23 - 0
dropwizard/src/main/java/com/example/helloworld/resources/views/FortuneView.java

@@ -0,0 +1,23 @@
+package com.example.helloworld.resources.views;
+
+import com.example.helloworld.db.model.Fortune;
+import io.dropwizard.views.View;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+public class FortuneView extends View {
+
+    private final List<Fortune> fortunes;
+
+    public FortuneView(List<Fortune> fortunes) {
+        super("/fortunes.mustache", StandardCharsets.UTF_8);
+
+        this.fortunes = fortunes;
+    }
+
+    @SuppressWarnings("unused")
+    public List<Fortune> getFortunes() {
+        return fortunes;
+    }
+}

+ 14 - 0
dropwizard/src/main/resources/fortunes.mustache

@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+        <table>
+            <tr><th>id</th><th>message</th></tr>
+{{#fortunes}}
+                <tr><td>{{id}}</td><td>{{message}}</td></tr>
+{{/fortunes}}
+        </table>
+    </body>
+</html>