Couchbase Java SDK 2.0.0 Developer Preview 2
Originally written by Michael Nitschinger
On behalf of the whole SDK team I'm glad to announce the second developer preview of the Java/JVM SDK release train nicknamed Armstrong. It currently contains both the JVM core package "core-io" 0.2 as well as the Java SDK 2.0 preview 2. Aside from maturing significantly over the first developer preview, it now provides rebalance support, adds APIs for both View and N1QL DSLs, has the flush command implemented and much more. This blog post will run you through the most important bits.
Before we dig into the new features, here is how you can get it:
<dependencies> <dependency> <groupId>com.couchbase.client</groupId> <artifactId>couchbase-client</artifactId> <version>2.0.0-dp2</version> </dependency> </dependencies> <repositories> <repository> <id>couchbase</id> <name>couchbase repo</name> <url>http://files.couchbase.com/maven2</url> <snapshots><enabled>false</enabled></snapshots> </repository> </repositories>
Logging
While not a new feature itself, the new SDK uses SLF4J exclusively now. So if you want to enable logging you can add a logger dependency like this:
<dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.2</version> </dependency> </dependencies>
This will give you DEBUG level logging by default, but you can use the logback configuration to change it to INFO level if you need to (logback.xml):
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- set level to trace for packet-level output --> <root level="info"> <appender-ref ref="STDOUT" /> </root> </configuration>
Easy Configuration
The first developer preview already had it, but we didn't announce it at the time. For this new SDK, we are using the Typesafe Config library, which provides a versatile way to configure your application and libraries. We certainly believe that this is also a library that you can reuse in your own applications, since it provides a wide range of useful methods and configuration options. Here are some possibilities in their search order:
- system properties
- application.conf (all resources on classpath with this name)
- application.json (all resources on classpath with this name)
- application.properties (all resources on classpath with this name)
- reference.conf (all resources on classpath with this name)
The SDK ships with a reference.conf as the default implementation, so all system properties or config files that you put in your classpath will override them. It's as easy as this. As of dp2, the `reference.conf` has lots of options, here are the most common one to tune:
com.couchbase.client { queryEnabled = false bootstrap { sslEnabled = false sslKeystoreFile = "" sslKeystorePassword = "" http { enabled = true } carrier { enabled = true } } io.poolSize = 0 }
You can see that the couchbase settings are properly namespaced so they don't interfer with the ones in your application. Let's say you want to enable the experimental N1QL querying. You can do that either through an application.conf file (if you are using maven, just put it in the resources folder) like this:
com.couchbase.client.queryEnabled = true
or
com.couchbase.client { queryEnabled = true }
Or if you want to use a system property (make sure to set it before you initialize the cluster object):
System.setProperty("com.couchbase.client.queryEnabled", "true");
All options will be properly documented in the future, but with these instructions it should be easy to override any configuration setting that you need. One note of warning though: override only those settings which you understand the impact of. There are also advanced settings to tune like ring buffer sizes which can have an impact on how your application behaves in certain situations and environments.
Rebalance support
The core package has been extended to support rebalance (adding, removing, failing over nodes) while it is running, so it is now possible to change your cluster configuration while you are running your workloads. This is something that we mark as "basic functionality" and should work with all different setups, but it is still undergoing testing. Please file any bugs that you find, especially around rebalance. We want to make sure that this is rock solid when we release the final version.
Note that there is a known issue that in some cases, operations are never completed. Make sure for this developer preview that you always chain a `timeout` in your observable to make sure your codepath moves forward even if the operation does not complete during rebalance.
Observable<JsonDocument> doc = bucket.get("key").timeout(5, TimeUnit.SECONDS);
Also, if you have N1QL enabled, make sure that the query server is running on every node that you add to the cluster, since it tries to pick it up from there. As N1QL integrates more closely with Couchbase Server, this will require less manual setup.
N1QL DSL
One of the major new features is a DSL for N1QL queries, which is "intelligent" in that it guides you on the supported syntax. This is inspired by JooQ and implemented through interface hierachies. You can now specify N1QL queries like this (and if you type it in your IDE see how you get autocomplete support for the allowed next steps implicitly):
System.setProperty("com.couchbase.client.queryEnabled", "true"); Cluster cluster = new CouchbaseCluster(); Bucket bucket = cluster.openBucket().toBlocking().single(); Observable<QueryResult> results = bucket.query( select("firstname", "lastname").from("users").where(x("age").gt(x(18))) ); results.subscribe(result -> System.out.println(result.value().getString("firstname") + result.value().getString("lastname")) );
An example of how this looks in IntelliJ, my IDE while typing:

There are a few things going on here in the query method itself. First, the query method uses a few static imports to make the DSL more fluent. The first one is select (from com.couchbase.client.java.query.Select.select) which starts the DSL. The other one that you can see here is "x" (from com.couchbase.client.java.query.dsl.Expression.x), which acts as a shorthand for an expression. Everywhere N1QL supports an expression, it can be expressed as a expression in the DSL as well. Expressions allow you to nicely and type-safely create different types of statements (like the one shown above). In future releases we will add more overloads and functions to provide even better support for the full N1QL specification. You can also use the "s" static import. If used as a replacement for "x", it will automatically quote your expression.
View DSL
While we did put great emphasis on a fluent N1QL DSL, we did not forget our excellent Views of course (which, spoiler alert, will get even better with the next Couchbase Server release!). The new SDK also features a View DSL, very similar to the one you've read just a minute ago:
Cluster cluster = new CouchbaseCluster(); Bucket bucket = cluster.openBucket().toBlocking().single(); Observable<ViewResult> query = bucket.query(ViewQuery.from("designdoc", "view").limit(10).reduce()); query.subscribe(result -> System.out.println(result.value()));
This developer preview does not have "include docs" yet, but thanks to our observables this is very easy to fix (but for sure we will add support for it soon):
Observable<ViewResult> query = bucket.query(ViewQuery.from("brewery", "by_name").limit(10).reduce()); query .flatMap(result -> bucket.get(result.id())) .subscribe(doc -> System.out.println(doc.content()));
Flush
Especially during development, and if enabled on the server side, you can flush your bucket easily. This will remove all the documents from your bucket, which is especially handy during testing. Do be aware though that flush can take a while (this is being tracked on Couchbase Server as an issue):
bucket.flush();
We are currently using something very similar in some integration tests:
@BeforeClass public static void connect() { cluster = new CouchbaseCluster(seedNode); bucket = cluster.openBucket(bucketName, password).toBlocking().single(); bucket.flush().toBlocking().single(); }
SSL Encryption
There will be a separate blog post about it later, but we can't resist giving you some hints now. The next major server version will include support for client-side encryption, and this developer preview already has the support built in.
In order to enable it, you need to do two things:
- First, get the server certificate and add it to your JVM keystore. (Supported releases of the server have this in the UI)
- Second, enable it on the client side.
The first step is not specific to the couchbase SDK, and most of you will be familiar with the "keytool" command that is used to import a certificate. Here is one way to do it:
keytool -import -file <certificate>
You can also specify a custom keystore, password and so on. Also, the place of the default keystore file depends on your platform. For now, please consult the keytool docs for more info in case you need it.
The second step is to enable it in the configuration:
com.couchbase.client.bootstrap { sslEnabled = true sslKeystoreFile = /path/to/keystorefile sslKeystorePassword = "" }
That's all you need to do! Enable it, give it the path to the keystore and the password of it (optionally if set). The client will automatically negotiate everything and run the data over encrypted connections.
Next Release
The next release is most probably going to be a beta release where we aim for feature completeness (replica read, durability requirements for persistence/replication, design document management, ...) and focus on first-class documentation. Please file any issues you find here and provide feedback through comments here or the developer mailing list. We also have advanced features in the pipeline like legacy and custom converters, thanks to some source code contributions already.
Comments