NoSQL Zone is brought to you in partnership with:

Don Pinto is a Product Marketing Manager with experience in cloud and database technologies. Don is a DZone MVB and is not an employee of DZone and has posted 91 posts at DZone. You can read more from them at their website. View Full User Profile

Couchbase Java SDK 2.0.0 Developer Preview 3

08.15.2014
| 3426 views |
  • submit to reddit

Originally written by Michael Nitschinger

On behalf of the whole SDK team I'm happy to announce the third developer preview of the Java/JVM SDK release train nicknamed Armstrong. It contains both the JVM core package "core-io" 0.3 as well as the Java SDK 2.0 developer preview 3.

This preview provides many more APIs which bring us closer to API completion (and a beta release to follow), as well as changes to configuration management and dependencies.

Here is how you can get it:

<dependencies>
    <dependency>
        <groupId>com.couchbase.client</groupId>
        <artifactId>couchbase-client</artifactId>
        <version>2.0.0-dp3</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>

Dependency Changes

Every dependency increases the possibility of version conficts with user libraries. In an effort to reduce the likelyhood, we made the following changes:

  • Getting rid of non-essential dependencies.
  • Package internal-only dependencies into a "fat jar" and move their packages to avoid clashing.

We've removed hard dependencies to SLF4J (and added optional support for more) and to the Typesafe Config library. While removing the Config library leaves us with potentially less features when it comes to configuration management, we made sure to implement a nice builder DSL on our own, which can also be configured through system properties. 

The "core-io" package now shadows internal dependencies like the LMAX Disruptor, Netty and Jackson. This not only makes it less likely that the SDK conflicts with other versions of those dependencies, but also allows us to freely upgrade those packages as we see fit, and even replace them with something else completely and users won't take notice or need to change something in their application stack.

From this developer preview on forward, the SDK only has two explicit dependencies: the core-io package and RxJava. RxJava cannot be shadowed because it is the primary interface of our asynchronous APIs and a vital part of building applications with the SDK.

New Configuration Builder API & Connection String

One thing on the "todo" list became very important with the removal of the config library: a builder DSL for a cluster configuration with sensible defaults and the ability to configure them through system properties as well.

The ordering of settings is now as follows (highes precedence first):

  • System Properties
  • Builder settings
  • Default values

This allows you to override default settings through the builder for all of your deployments, but in different environments override specific settings through system properties on the fly when you start up the JVM/container.

Also initial support for the "connection string" has been added, which provides similar bootstrap semantics across all of our official SDKs. For that purpose, the construction of the "CouchbaseCluster" object has been changed to factory methods which provide greater flexibility. If you don't care about custom settings you can use one of these:

// Default settings & localhost
CouchbaseCluster.create();

// Default settings & vararg list of nodes
CouchbaseCluster.create("192.168.56.101", "192.168.56.102");

// Default settings & list of nodes
List<String> nodes = Arrays.asList("192.168.56.101", "192.168.56.102");
CouchbaseCluster.create(nodes);

If you want to use the connection string API (which is not covered here in detail) you can use the `fromConnectionString` method instead:

CouchbaseCluster.fromConnectionString("couchbase://192.168.56.101,192.168.56.102");

All of the shown methods have additional overloads that allow it to pass in a "ClusterEnvironment". The environment is a stateful component which also contains properties (the settings that you can change).

So, enabling N1QL querying for example works like this (and we still want to connect to localhost):

ClusterEnvironment environment = DefaultClusterEnvironment.create(
    DynamicClusterProperties.builder()
        .queryEnabled(true)
        .build()
);
CouchbaseCluster.create(environment);

Note that we might further streamline this API for the beta release, so expect slight changes in that area.

The environment contains, apart from the configurable properties, important bits and pieces of the SDK runtime (including various thread pools for proper functioning) and it is designed to be re-used across CouchbaseCluster objects. This means that it doesn't matter if you connect to multiple buckets in one cluster or to multiple clusters, ressouces can be shared and are optimally allocated.

Now if you don't want to use the builder, but instead set system properties, the "dynamic properties", which are also used by default, listen on specific properties as well. This is another way to enable querying (or even to override a builder setting):

System.setProperty("com.couchbase.queryEnabled", "true");
CouchbaseCluster cluster = CouchbaseCluster.create();

The Legacy Transcoder

To be compatible with older applications, we've implemented a LegacyTranscoder/LegacyDocument which sets and understands flags, compression and object serialization like the one of the 1.4.* series (and older) does. Since the APIs are not bound to any specific transcoder, it can be used through the same API as the JsonTranscoder (and the corresponding JsonDocument).

// Will be stored as a string on the server, can also be a JSON string
bucket.upsert(LegacyDocument.create("legacydoc-string", "mystring"));

// Will be stored as a number
bucket.upsert(LegacyDocument.create("legacydoc-int", 25));

// A POJO that will be serialized if serializable
bucket.upsert(LegacyDocument.create("legacydoc-pojo", user));

The data can be loaded as well:

// Loads a legacy document based on the ID.
bucket.get("legacydoc", LegacyDocument.class);

// Also loads the legacy document and infers its document by the input.
bucket.get(LegacyDocument.create("legacydoc"));

Changes to View & Query API

We made some slight changes to the View and N1QL query APIs to give you more information during error and debugging scenarios. Previously, all query method returned the rows directly, but there is associated information available (querying statistics, error messages,...) which could not be exposed through such an interface.

Now the query methods return results, which itself contain an observable to get to the actual rows or other information. Here is how you can query a view but also log debug information.

bucket
    .query(ViewQuery.from("design", "view"))
    .doOnNext(result -> {
        if (!result.success()) {
            System.err.println(result.error());
        }
    })
    .flatMap(ViewResult::rows)
    .subscribe(row -> System.out.println(row.id()));

You can use the "doOnNext" to add a side-effect and if the result is not successful, log the error. If you don't care about other parts than the actual rows, you can use flatMap directly to get the rows out as before. We've also added the possibility to load the full document contents if "withDocuments" is set:

bucket
    .query(ViewQuery.from("design", "view").withDocuments())
    .flatMap(ViewResult::rows)
    .flatMap(ViewRow::document)
    .subscribe(System.out::println);

Since every ViewRow provides a way to load the full document, you can use flatMap to get the full document (which internally uses get calls) and then print it instead of just the ID.

The same API is used for N1QL queries, but "info" output is itself an Observable because internally it is streamed after the returned rows.

Published at DZone with permission of Don Pinto, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)