あいつの日誌β

働きながら旅しています。

Dropwizard 0.7.1 tutorial

this article is copied from Day 13: Dropwizard -- The Awesome Java REST Server Stack

Setting Up Maven

% mvn archetype:create -DgroupId=com.example -DartifactId=myblog
% cd myblog
% git init
% git add .
% git commit -m 'initial commit' 

create .gitignore:

.idea/
*.iml
target/
% git add .gitignore
% git commit -m 'add .gitignore' 

Updating the pom.xml

update pom.xml:

diff --git a/pom.xml b/pom.xml
index 2ff8c7f..0e4df99 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
 
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <dropwizard.version>0.7.1</dropwizard.version>
   </properties>
 
   <dependencies>
@@ -21,5 +22,49 @@
       <version>3.8.1</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>io.dropwizard</groupId>
+      <artifactId>dropwizard-core</artifactId>
+      <version>${dropwizard.version}</version>
+    </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>1.6</version>
+        <configuration>
+            <createDependencyReducedPom>true</createDependencyReducedPom>
+            <filters>
+                <filter>
+                    <artifact>*:*</artifact>
+                    <excludes>
+                        <exclude>META-INF/*.SF</exclude>
+                        <exclude>META-INF/*.DSA</exclude>
+                        <exclude>META-INF/*.RSA</exclude>
+                    </excludes>
+                </filter>
+            </filters>
+        </configuration>
+        <executions>
+            <execution>
+                <phase>package</phase>
+                <goals>
+                    <goal>shade</goal>
+                </goals>
+                <configuration>
+                    <transformers>
+                        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                            <mainClass>com.example.myblog.MyBlogApplication</mainClass>
+                        </transformer>
+                    </transformers>
+                </configuration>
+            </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 </project>

install dependency

% mvn clean install
% git add pom.xml
% git commit -m 'add dropwizard.version, dependency and maven-shade plugins' 

Creating Configuration class

create src/main/java/com/example/myblog/MyBlogConfiguration.java:

package com.example.myblog;

import io.dropwizard.Configuration;

public class MyBlogConfiguration extends Configuration {
}
% git add src/main/java/com/example/myblog/MyBlogConfiguration.java
% git commit -m 'create configuration class'

※ name, template が必須?

Creating Application class

create src/main/java/com/example/myblog/MyBlogApplication.java:

package com.example.myblog;

import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;

public class MyBlogApplication extends Application<MyBlogConfiguration> {
    public static void main(String[] args) throws Exception {
        new MyBlogApplication().run(args);
    }

    @Override
    public String getName() {
        return "my-blog";
    }

    @Override
    public void initialize(Bootstrap<MyBlogConfiguration> bootstrap) {
        // nothing to do yet
    }

    @Override
    public void run(MyBlogConfiguration configuration,
                    Environment environment) throws Exception {
        // nothing to do yet
    }

}
% git add src/main/java/com/example/myblog/MyBlogApplication.java
% git commit -m 'create application class'

Creating A Representation Class

create src/main/java/com/example/myblog/core/Blog.java:

package com.example.myblog.core;

import java.util.Date;
import java.util.UUID;
 
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.URL;
 
public class Blog {

    private String id = UUID.randomUUID().toString();
 
    @NotBlank
    private String title;
 
    @URL
    @NotBlank
    private String url;
 
    private final Date publishedOn = new Date();
 
    public Blog() {
    }
 
    public Blog(String title, String url) {
        super();
        this.title = title;
        this.url = url;
    }
 
    public String getId() {
        return id;
    }
 
    public String getTitle() {
        return title;
    }
 
    public String getUrl() {
        return url;
    }
 
    public Date getPublishedOn() {
        return publishedOn;
    }
}
% git add src/main/java/com/example/myblog/core/Blog.java
% git commit -m 'create representation class'

Creating Resource class

create src/main/java/com/example/myblog/resources/IndexResource.java:

package com.example.myblog.resources;

import java.util.Arrays;
import java.util.List;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
 
import com.codahale.metrics.annotation.Timed;
import com.example.myblog.core.Blog;
 
@Path("/")
public class IndexResource {
 
    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public List<Blog> index() {
        return Arrays.asList(new Blog("getting started dropwizard 0.7.0",
                "http://okamuuu.hatenablog.com/entry/2014/11/06/192836"));
    }
}

and update MyBlogApplication.java:

diff --git a/src/main/java/com/example/myblog/MyBlogApplication.java b/src/main/java/com/example/myblog/MyBlogApplication.java
index f64d82d..81c8ab4 100644
--- a/src/main/java/com/example/myblog/MyBlogApplication.java
+++ b/src/main/java/com/example/myblog/MyBlogApplication.java
@@ -4,6 +4,8 @@ import io.dropwizard.Application;
 import io.dropwizard.setup.Bootstrap;
 import io.dropwizard.setup.Environment;
 
+import com.example.myblog.resources.IndexResource;
+
 public class MyBlogApplication extends Application<MyBlogConfiguration> {
     public static void main(String[] args) throws Exception {
         new MyBlogApplication().run(args);
@@ -22,7 +24,9 @@ public class MyBlogApplication extends Application<MyBlogConfiguration> {
     @Override
     public void run(MyBlogConfiguration configuration,
                     Environment environment) throws Exception {
-        // nothing to do yet
+        
+        final IndexResource indexResource = new IndexResource();
+        environment.jersey().register(indexResource);
     }
 
 }
% git add src/main/java/com/example/myblog/MyBlogApplication.java
% git add src/main/java/com/example/myblog/resources/IndexResource.java
% git commit -m 'add IndexResource'

Running Application

% mvn package

run it.

% java -jar target/myblog-1.0-SNAPSHOT.jar server

check it.

% curl http://localhost:8080                                                                 [{"id":"083541a0-29bc-474a-b1ec-dae598bbafc1","title":"getting started dropwizard 0.7.0","url":"http://okamuuu.hatenablog.com/entry/2014/11/06/192836","publishedOn":1416107023288}]

Configuring MongoDB

update pom.xml

diff --git a/pom.xml b/pom.xml
index 0e4df99..ed89c53 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,6 +27,11 @@
       <artifactId>dropwizard-core</artifactId>
       <version>${dropwizard.version}</version>
     </dependency>
+    <dependency>
+      <groupId>net.vz.mongodb.jackson</groupId>
+      <artifactId>mongo-jackson-mapper</artifactId>
+      <version>1.4.2</version>
+    </dependency>
   </dependencies>
 
   <build>
% git add pom.xml
% git commit -m 'add mongo-jackson-mapper to dependency'
% mvn clean install

create myblog.yml

mongoHost: localhost
mongoPort: 27017
mongoDb: myblog

update src/main/java/com/example/myblog/MyBlogConfiguration.java:

package com.example.myblog;

import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

public class MyBlogConfiguration extends Configuration {

    @JsonProperty
    @NotEmpty
    private String mongoHost = "localhost";

    @JsonProperty
    @Min(1)
    @Max(65535)
    private int mongoPort = 27017;

    @JsonProperty
    @NotEmpty
    private String mongoDb = "myblog";

    @JsonProperty
    public String getMongoHost() {
        return mongoHost;
    }

    @JsonProperty
    public void setMongoHost(String host) {
        this.mongoHost = host;
    }

    @JsonProperty
    public int getMongoPort() {
        return mongoPort;
    }

    @JsonProperty
    public void setMongoPort(int port) {
        this.mongoPort = port;
    }

    @JsonProperty
    public String getMongoDb() {
        return mongoDb;
    }

    @JsonProperty
    public void setMongoDb(String db) {
        this.mongoDb = db;
    }
}
% git add myblog.yml
% git add src/main/java/com/example/myblog/MyBlogConfiguration.java
% git commit -m 'add mongoDB configuration'

create src/main/java/com/example/myblog/MongoManaged.java:

package com.example.myblog;

import com.mongodb.Mongo;
import io.dropwizard.lifecycle.Managed;

public class MongoManaged implements Managed {

    private Mongo mongo;

    public MongoManaged(Mongo mongo) {
        this.mongo = mongo;
    }

    @Override
    public void start() throws Exception {
    }

    @Override
    public void stop() throws Exception {
        mongo.close();
    }
}

update src/main/java/com/example/myblog/MyBlogApplication.java

diff --git a/src/main/java/com/example/myblog/MyBlogApplication.java b/src/main/java/com/example/myblog/MyBlogApplication.java
index 81c8ab4..ce938eb 100644
--- a/src/main/java/com/example/myblog/MyBlogApplication.java
+++ b/src/main/java/com/example/myblog/MyBlogApplication.java
@@ -6,6 +6,8 @@ import io.dropwizard.setup.Environment;
 
 import com.example.myblog.resources.IndexResource;
 
+import com.mongodb.Mongo;
+
 public class MyBlogApplication extends Application<MyBlogConfiguration> {
     public static void main(String[] args) throws Exception {
         new MyBlogApplication().run(args);
@@ -25,6 +27,10 @@ public class MyBlogApplication extends Application<MyBlogConfiguration> {
     public void run(MyBlogConfiguration configuration,
                     Environment environment) throws Exception {
         
+        Mongo mongo = new Mongo(configuration.getMongoHost(), configuration.getMongoPort());
+        MongoManaged mongoManaged = new MongoManaged(mongo);
+        environment.lifecycle().manage(mongoManaged);
+
         final IndexResource indexResource = new IndexResource();
         environment.jersey().register(indexResource);
     }
% git add src/main/java/com/example/myblog/MyBlogApplication.java
% git add src/main/java/com/example/myblog/MongoManaged.java
% git commit -m 'add Mongo lifecycle managed class'
% mvn celan install

Add HealthCheck

create src/main/java/com/example/myblog/health/MongoHealthCheck.java

package com.example.myblog.health;

import com.mongodb.Mongo;
import com.codahale.metrics.health.HealthCheck;

public class MongoHealthCheck extends HealthCheck {

    private final Mongo mongo;

    public MongoHealthCheck(Mongo mongo) {
        this.mongo = mongo;
    }   

    @Override
    protected Result check() throws Exception {
        mongo.getDatabaseNames();
        return Result.healthy();
    }   
}

update src/main/java/com/example/myblog/MyBlogApplication.java:

diff --git a/src/main/java/com/example/myblog/MyBlogApplication.java b/src/main/java/com/example/myblog/MyBlogApplication.java
index 81c8ab4..902ff86 100644
--- a/src/main/java/com/example/myblog/MyBlogApplication.java
+++ b/src/main/java/com/example/myblog/MyBlogApplication.java
@@ -5,6 +5,9 @@ import io.dropwizard.setup.Bootstrap;
 import io.dropwizard.setup.Environment;
 
 import com.example.myblog.resources.IndexResource;
+import com.example.myblog.health.MongoHealthCheck;
+
+import com.mongodb.Mongo;
 
 public class MyBlogApplication extends Application<MyBlogConfiguration> {
     public static void main(String[] args) throws Exception {
@@ -25,6 +28,14 @@ public class MyBlogApplication extends Application<MyBlogConfiguration> {
     public void run(MyBlogConfiguration configuration,
                     Environment environment) throws Exception {
         
+        Mongo mongo = new Mongo(configuration.getMongoHost(), configuration.getMongoPort());
+        MongoManaged mongoManaged = new MongoManaged(mongo);
+        environment.lifecycle().manage(mongoManaged);
+
+        final MongoHealthCheck mongoHealthCheck =
+          new MongoHealthCheck(mongo);
+        environment.healthChecks().register("mongo", mongoHealthCheck);
+
         final IndexResource indexResource = new IndexResource();
         environment.jersey().register(indexResource);
     }
% git add src/main/java/com/example/myblog/MyBlogApplication.java
% git add src/main/java/com/example/myblog/health/MongoHealthCheck.java
% git commit -m 'add MongoHealthCheck'

check

% java -jar target/myblog-1.0-SNAPSHOT.jar server myblog.yml
% curl http://localhost:8081/healthcheck
{"deadlocks":{"healthy":true},"mongo":{"healthy":true}

Create BlogResource

update src/main/java/com/example/myblog/core/Blog.java

package com.example.myblog.core;

import java.util.Date;

import net.vz.mongodb.jackson.Id;
import net.vz.mongodb.jackson.ObjectId;

import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.URL;
import com.fasterxml.jackson.annotation.JsonCreator;

public class Blog {

    @Id
    public String id;

    @NotBlank
    public String title;

    @URL
    @NotBlank
    public String url;

    public final Date publishedOn = new Date();

}

update src/main/java/com/example/myblog/resources/IndexResource.java:

package com.example.myblog.resources;

import java.util.ArrayList;
import java.util.List;

import com.example.myblog.core.Blog;
import com.google.common.base.Optional;
import com.codahale.metrics.annotation.Timed;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.concurrent.atomic.AtomicLong;

import net.vz.mongodb.jackson.DBCursor;
import net.vz.mongodb.jackson.JacksonDBCollection;

@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public class IndexResource {

    private JacksonDBCollection<Blog, String> collection;

    public IndexResource(JacksonDBCollection<Blog, String> blogs) {
      this.collection = blogs;
    }

    @GET
    @Timed
    public List<Blog> index() {
        DBCursor<Blog> dbCursor = collection.find();
        List<Blog> blogs = new ArrayList<Blog>();
        while (dbCursor.hasNext()) {
            Blog blog = dbCursor.next();
            blogs.add(blog);
        }
        return blogs;
    }
}

create src/main/java/com/example/myblog/resources/BlogResource.java:

package com.example.myblog.resources;

import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import net.vz.mongodb.jackson.DBCursor;
import net.vz.mongodb.jackson.JacksonDBCollection;

import com.example.myblog.core.Blog;
import com.codahale.metrics.annotation.Timed;

@Path("/blogs")
@Produces(value = MediaType.APPLICATION_JSON)
@Consumes(value = MediaType.APPLICATION_JSON)
public class BlogResource {

  private JacksonDBCollection<Blog, String> collection;

    public BlogResource(JacksonDBCollection<Blog, String> blogs) {
      this.collection = blogs;
    }

    @GET
    @Timed
    public List<Blog> blogsTimeLine() {
        DBCursor<Blog> dbCursor = collection.find();
        List<Blog> blogs = new ArrayList<Blog>();
        while (dbCursor.hasNext()) {
            Blog blog = dbCursor.next();
            blogs.add(blog);
        }
        return blogs;
    }

    @POST
    @Timed
    public Response publishNewBlog(@Valid Blog blog) {
        collection.insert(blog);
        return Response.noContent().build();
    }
}

update src/main/java/com/example/myblog/MyBlogApplication.java:

package com.example.myblog;

import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;

import com.example.myblog.core.Blog;
import com.example.myblog.resources.IndexResource;
import com.example.myblog.resources.BlogResource;
import com.example.myblog.health.MongoHealthCheck;

import com.mongodb.Mongo;
import com.mongodb.DB;
import net.vz.mongodb.jackson.JacksonDBCollection;

public class MyBlogApplication extends Application<MyBlogConfiguration> {
    public static void main(String[] args) throws Exception {
        new MyBlogApplication().run(args);
    }

    @Override
    public String getName() {
        return "my-blog";
    }

    @Override
    public void initialize(Bootstrap<MyBlogConfiguration> bootstrap) {
        // nothing to do yet
    }

    @Override
    public void run(MyBlogConfiguration configuration,
                    Environment environment) throws Exception {
        
        Mongo mongo = new Mongo(configuration.getMongoHost(), configuration.getMongoPort());
        MongoManaged mongoManaged = new MongoManaged(mongo);
        environment.lifecycle().manage(mongoManaged);

        final MongoHealthCheck mongoHealthCheck =
          new MongoHealthCheck(mongo);
        environment.healthChecks().register("mongo", mongoHealthCheck);

        DB db = mongo.getDB(configuration.getMongoDb());
        JacksonDBCollection<Blog, String> blogs = JacksonDBCollection.wrap(db.getCollection("blogs"), Blog.class, String.class);

        final IndexResource indexResource = new IndexResource(blogs);
        environment.jersey().register(indexResource);

        final BlogResource blogResource = new BlogResource(blogs);
        environment.jersey().register(blogResource);
    }

}
% git add src/main/java/com/example/myblog/MyBlogApplication.java
% git add src/main/java/com/example/myblog/core/Blog.java
% git add src/main/java/com/example/myblog/resources/BlogResource.java
% git commit -m 'use mongoDB'
curl -i -X POST -H "Content-Type: application/json" -d '{"title":"getting started dropwizard 0.7.0 part2","url":"http://okamuuu.hatenablog.com/entry/2014/11/12/145356"}' http://localhost:8080/blogs

HTTP/1.1 204 No Content
Date: Sun, 16 Nov 2014 03:53:20 GMT
Content-Type: application/json
% curl http://localhost:8080
[{"id":"5467c915300414290c4253a6","title":"getting started dropwizard 0.7.0","url":"http://okamuuu.hatenablog.com/entry/2014/11/06/192836","publishedOn":1416087829129},{"id":"54681fb0300467ec3b406434","title":"getting started dropwizard 0.7.0 part2","url":"http://okamuuu.hatenablog.com/entry/2014/11/12/145356","publishedOn":1416110000144}]
% curl http://localhost:8080/blogs
[{"id":"5467c915300414290c4253a6","title":"getting started dropwizard 0.7.0","url":"http://okamuuu.hatenablog.com/entry/2014/11/06/192836","publishedOn":1416087829129},{"id":"54681fb0300467ec3b406434","title":"getting started dropwizard 0.7.0 part2","url":"http://okamuuu.hatenablog.com/entry/2014/11/12/145356","publishedOn":1416110000144}]