Build Status: Coverage Status:
Stories Ready:
dropwizard-couchbase is a Dropwizard bundle for Couchbase persistence.
The current version is 0.9.1 and it has the following dependencies:
- io.dropwizard dropwizard-core 1.1.1 (provided)
- com.couchbase.client couchbase-client 2.4.5 (compile time)
dropwizard-couchbase is compiled against JDK 8.
Add the following dependency to your build.gradle
dependencies {
compile "io.smartmachine:dropwizard-couchbase:0.9.1"
}or pom.xml
<project>
...
<dependencies>
<dependency>
<groupId>io.smartmachine</groupId>
<artifactId>dropwizard-couchbase</artifactId>
<version>0.9.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
Add a CouchbaseBundle to your Application class:
packageio.sample;
importio.dropwizard.Application;
importio.dropwizard.setup.Bootstrap;
importio.dropwizard.setup.Environment;
importio.smartmachine.couchbase.CouchbaseBundle;
publicclassConfigurationServerextendsApplication<ConfigurationServerConfig> {
publicstaticvoidmain(String[] args) throwsException {
newConfigurationServer().run(args);
}
privatefinalCouchbaseBundle<ConfigurationServerConfig> couchbaseBundle = newCouchbaseBundle<ConfigurationServerConfig>() {
@OverridepublicCouchbaseClientFactorygetCouchbaseClientFactory(ConfigurationServerConfigconfiguration) {
returnconfiguration.getCouchbaseClientFactory();
}
};
@Overridepublicvoidinitialize(Bootstrap<ConfigurationServerConfig> bootstrap) {
bootstrap.addBundle(couchbaseBundle);
}
@Overridepublicvoidrun(ConfigurationServerConfigconfiguration, Environmentenvironment) throwsException {
// Register all your resources here as usual
}
@OverridepublicStringgetName() {
return"configuration-server";
}
}Implement your configuration class.
packageio.smartmachine.cs;
importcom.fasterxml.jackson.annotation.JsonProperty;
importio.dropwizard.Configuration;
importorg.hibernate.validator.constraints.NotEmpty;
importjavax.validation.Valid;
importjavax.validation.constraints.NotNull;
classConfigurationServerConfigextendsConfiguration {
// All your usual setup goes here@Valid@NotNullprivateCouchbaseClientFactoryccf = newCouchbaseClientFactory();
@JsonProperty("couchbase")
publicCouchbaseClientFactorygetCouchbaseClientFactory() {
returnccf;
}
@JsonProperty("couchbase")
publicvoidsetCouchbaseClientFactory(CouchbaseClientFactoryccf) {
this.ccf = ccf;
}
}Add the following to your yaml configuration file:
# Your server configurationserver:
applicationConnectors:
- type: httpport: 9000adminConnectors:
- type: httpport: 9001# Default Couchbase Configurationcouchbase:
bucket: defaulthosts:
- http://localhost:8091/poolspassword: ""If you don't add a couchbase configuration section to your yaml the defaults (above) will be assumed. More CouchbaseClient configuration options will be added in the future.
dropwizard-couchbase will autogenerate DAO implementation classes and views for you to facilitate standard CRUD operations.
We assume that you have a standard dropwizard resource class as well as a model class with the appropriate JsonProperty and JsonCreator annotations for Jackson de/serialization. Let's look at such a class, called Device.java:
packageio.sample.api;
importcom.fasterxml.jackson.annotation.JsonCreator;
importcom.fasterxml.jackson.annotation.JsonProperty;
importorg.hibernate.validator.constraints.Length;
importorg.hibernate.validator.constraints.NotEmpty;
importjava.util.List;
publicclassDevice {
@Length(min = 12, max=12)
@NotEmptyprivatefinalStringserial;
privateList<String> modules;
@JsonCreatorpublicDevice(@JsonProperty("serial") Stringserial) {
this.serial = serial;
}
@JsonPropertypublicvoidsetModules(List<String> modules) {
this.modules = modules;
}
@JsonPropertypublicList<String> getModules() {
returnmodules;
}
@JsonPropertypublicStringgetSerial() {
returnserial;
}
}In order to enable automatic DAO generation you need to write an Accessor interface (similar to DAO class/interface in JPA/Hibernate):
packageio.sample.api;
importio.smartmachine.couchbase.GenericAccessor;
importio.smartmachine.couchbase.CouchbaseView;
importjava.util.List;
publicinterfaceDeviceAccessorextendsGenericAccessor<Device> {
@ViewQuery("/^DEVICE/.test(meta.id)")
publicList<Device> findAll();
}The findall() method will be autogenerated. The @ViewQuery annotation will generate a Couchbase Design Document called DEVICE with a view called findAll like so:
function(doc,meta){if(/^DEVICE/.test(meta.id)){emit(meta.id,null);}}The emit statement can be controlled as well, emit(meta.id, null) is the default. The following annotation will generate a view that emits full documents: @ViewQuery("/^DEVICE/.test(meta.id)", emit = "emit(meta.id, doc)"). Note that the name of the Design Document will be your model class .toUpperCase().
The extended GenericAccessor<Device> interface has the following contract, all methods will be automatically implemented:
packageio.smartmachine.couchbase;
publicinterfaceGenericAccessor<T> {
voidcreate(Stringid, Tnewinstance);
Tread(Stringid);
voidupdate(Stringid, Tobject);
voiddelete(Stringid);
voidset(Stringid, Tobject);
}Note that this is CRUD plus an extra set operation to conform with the provided methods of CouchbaseClient.
The last step is to annotate your Resource class as follows:
packageio.sample.resources;
importcom.codahale.metrics.annotation.Timed;
importio.sample.api.Device;
importio.sample.api.DeviceAccessor;
importio.smartmachine.couchbase.Accessor;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importjavax.validation.Valid;
importjavax.ws.rs.*;
importjavax.ws.rs.core.MediaType;
importjava.util.List;
@Path("/devices")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
publicclassDeviceResource {
privatestaticfinalLoggerlog = LoggerFactory.getLogger(DeviceResource.class);
// Note the Accessor annotation@AccessorprivateDeviceAccessoraccessor;
privatefinalList<String> defaultModules;
publicDeviceResource(List<String> defaultModules) {
this.defaultModules = defaultModules;
}
@GET@Path("{id}")
@TimedpublicDevicedevices(@PathParam("id") Stringid) {
returnaccessor.read(id);
}
@GET@TimedpublicList<Device> all() {
returnaccessor.findAll();
}
@PUT@Path("{id}")
@TimedpublicDeviceadd(@PathParam("id") Stringid, @ValidDevicedevice) {
if (device.getModules() == null || device.getModules().size() == 0) {
device.setModules(defaultModules);
}
accessor.create(id, device);
returndevice;
}
}Note the @Accessor annotation in the above example. dropwizard-couchbase will inject an implementation of DeviceAccessor for you to use in your Resource class.
If you want to do some more low-level stuff with CouchbaseClient you can use the following annotation in your Resource class in stead:
importio.smartmachine.couchbase.CouchbaseClientFactory;
importio.smartmachine.couchbase.ClusterManagerpublicclassDeviceResource {
@AccessorprivateCouchbaseClientFactoryfactory;
@GET@Path("{id}")
@TimedpublicDevicedevices(@PathParam("id") Stringid) {
CouchbaseClientclient = factory.client();
// and / orClusterManagermanager = factory.getClusterManager();
}
...
}- Implement full set of configuration options for CouchbaseClientFactory
- Implement proper Couchbase health checks and metrics
- Finish out unit tests
- Update Javadocs
Pull requests are very welcome. Create issues in the Github issue system for this repository against any bugs/feature requests.
dropwizard-couchbase is released under the MIT license.
