Couchbase Sdk Java 1.0

61
Couchbase Client Library: Java 1.0

Transcript of Couchbase Sdk Java 1.0

Page 1: Couchbase Sdk Java 1.0

Couchbase Client Library: Java 1.0

Page 2: Couchbase Sdk Java 1.0

Couchbase Client Library: Java 1.0

Abstract

This is the manual for 1.0 of the Couchbase Java client library, which is compatible with Couchbase Server 1.8.

This manual provides a reference to the key features and best practice for using the Java Couchbase Client libraries (couch-base-client and spymemcached). The content constitutes a reference to the core API, not a complete guide to the entire APIfunctionality.

Table 1. Product Compatibility for Couchbase SDK Java

Product Compatible All Features

Couchbase Server 1.8 ✓ ✓

Couchbase Server 2.0 ✓ ✗

Note. The following document is still in production, and is not considered complete or exhaustive.

Last document update: 12 Apr 2012 12:56; Document built: 12 Apr 2012 13:16.

Documentation Availability and Formats. This documentation is available online: HTML Online . For other documentation fromCouchbase, see Couchbase Documentation Library

Contact: [email protected] or couchbase.com

Copyright © 2010, 2011 Couchbase, Inc. Contact [email protected].

For documentation license information, see Section B.1, “Documentation License”. For all license information, see Appendix B, Licenses.

Page 3: Couchbase Sdk Java 1.0

iii

Table of Contents1. Getting Started ....................................................................................................................................... 1

1.1. Downloading the Couchbase Client Libraries .................................................................................... 11.2. Hello Couchbase .......................................................................................................................... 11.3. Couchbase API Overview .............................................................................................................. 31.4. A More Substantial Program .......................................................................................................... 41.5. How to Build and Run the Sample Application .................................................................................. 51.6. Conclusion .................................................................................................................................. 8

2. Tutorial ................................................................................................................................................. 92.1. Installation .................................................................................................................................. 92.2. Building a Chat Room Application .................................................................................................. 92.3. Connecting with the Server ............................................................................................................ 92.4. Configuring Logging ................................................................................................................... 112.5. Shutting Down a Client Connection ............................................................................................... 112.6. Increment and Decrement Operations ............................................................................................. 112.7. Prepend and Append Operations .................................................................................................... 122.8. Using Buckets ............................................................................................................................ 172.9. Error Handling ........................................................................................................................... 192.10. Using vbuckets ......................................................................................................................... 202.11. The Tutorial Example Code ........................................................................................................ 21

3. Using the APIs ..................................................................................................................................... 243.1. Connecting to a Couchbase Bucket ................................................................................................ 243.2. Connecting using Hostname and Port with SASL ............................................................................. 243.3. Shutting down the Connection ...................................................................................................... 25

4. Java Method Summary ........................................................................................................................... 264.1. Synchronous Method Calls ........................................................................................................... 274.2. Asynchronous Method Calls ......................................................................................................... 284.3. Object Serialization (Transcoding) ................................................................................................. 284.4. Expiry Values ............................................................................................................................ 29

5. Store Operations ................................................................................................................................... 305.1. Add Operations .......................................................................................................................... 305.2. Set Operations ............................................................................................................................ 31

6. Retrieve Operations ............................................................................................................................... 336.1. Synchronous get Methods .......................................................................................................... 336.2. Asynchronous get Methods ......................................................................................................... 346.3. Get-and-Touch Methods ............................................................................................................... 356.4. CAS get Methods ..................................................................................................................... 366.5. Bulk get Methods ..................................................................................................................... 38

7. Update Operations ................................................................................................................................. 417.1. Append Methods ........................................................................................................................ 417.2. Prepend Methods ........................................................................................................................ 427.3. Check-and-Set Methods ............................................................................................................... 437.4. Delete Methods .......................................................................................................................... 467.5. Decrement Methods .................................................................................................................... 477.6. Increment Methods ..................................................................................................................... 497.7. Replace Methods ........................................................................................................................ 507.8. Touch Methods .......................................................................................................................... 51

8. Statistics Operations .............................................................................................................................. 52A. Release Notes ...................................................................................................................................... 53

A.1. Release Notes for 1.0.2 Couchbase Client Library Java GA (5 April 2012) ........................................... 53A.2. Release Notes for 1.0.1 Couchbase Client Library Java GA (25 January 2012) ....................................... 53A.3. Release Notes for 1.0.0 Couchbase Client Library Java GA (23 January 2012) ....................................... 53

Page 4: Couchbase Sdk Java 1.0

Couchbase Client Library: Java 1.0

iv

B. Licenses .............................................................................................................................................. 55B.1. Documentation License ............................................................................................................... 55

Page 5: Couchbase Sdk Java 1.0

v

List of Figures2.1. Figure 1: Creating a private bucket. ....................................................................................................... 18

Page 6: Couchbase Sdk Java 1.0

vi

List of Tables1. Product Compatibility for Couchbase SDK Java ........................................................................................... 21.1. Synchronous Methods ........................................................................................................................... 31.2. Synchronous Check And Set .................................................................................................................. 31.3. Asynchronous Methods ......................................................................................................................... 41.4. Status Methods .................................................................................................................................... 44.1. Java Client Library Method Summary .................................................................................................... 265.1. Java Client Library Store Methods ......................................................................................................... 306.1. Java Client Library Retrieval Methods .................................................................................................... 337.1. Java Client Library Update Methods ...................................................................................................... 418.1. Java Client Library Statistics Methods .................................................................................................... 52

Page 7: Couchbase Sdk Java 1.0

1

Chapter 1. Getting Started

Now that you've installed Couchbase and have probably created a cluster of Couchbase servers, it is time to install theclient libraries, couchbase-client and spymemcached, and start storing data into the clusters.

Here's a quick outline of what you'll learn in this chapter:

1. Download the Java Couchbase Client Libraries, couchbase-client and spymemcached.

2. Create an Eclipse or NetBeans project and set up the Couchbase Client Libraries as referenced librares. You'll need toinclude these libraries at compile time, which should propogate to run time.

3. Write a simple program to demonstrate connecting to Couchbase and saving some data.

4. Explore some of the API methods that will take you further than the simple program.

1.1. Downloading the Couchbase Client Libraries

Download the Client libraries and its dependencies and make sure they are available in the classpath. Please refer to for in-stallation of the client JAR files and the dependencies and for running them. You can download them directly from the Ja-va client libraries for Couchbase.

These are Java Archive (.jar) files that you can use with your Java environment.

1.2. Hello Couchbase

You might be curious what the simplest Java program to talk to Couchbase might look like, and how you might compileand run it using just the Java command line tools. Follow along if you like and look at Listing 1.

Listing 1: Main.java

Page 8: Couchbase Sdk Java 1.0

Getting Started

2

import java.net.URI;import java.util.LinkedList;import java.util.List;import java.util.concurrent.TimeUnit;

import com.couchbase.client.CouchbaseClient;import net.spy.memcached.internal.GetFuture;import net.spy.memcached.internal.OperationFuture;

public class Main { public static final int EXP_TIME = 10; public static final String KEY = "spoon"; public static final String VALUE = "Hello World!";

public static void main(String args[]) { // Set the URIs and get a client List<URI> uris = new LinkedList<URI>();

Boolean do_delete = false;

// Connect to localhost or to the appropriate URI uris.add(URI.create("http://127.0.0.1:8091/pools"));

CouchbaseClient client = null; try { client = new CouchbaseClient(uris, "default", ""); } catch (Exception e) { System.err.println("Error connecting to Couchbase: " + e.getMessage()); System.exit(0); } // Do a synchrononous get Object getObject = client.get(KEY); // Do an asynchronous set OperationFuture<Boolean> setOp = client.set(KEY, EXP_TIME, VALUE); // Do an asynchronous get GetFuture getOp = client.asyncGet(KEY); // Do an asynchronous delete OperationFuture<Boolean> delOp = null; if (do_delete) { delOp = client.delete(KEY); } // Shutdown the client client.shutdown(3, TimeUnit.SECONDS); // Now we want to see what happened with our data // Check to see if our set succeeded try { if (setOp.get().booleanValue()) { System.out.println("Set Succeeded"); } else { System.err.println("Set failed: " + setOp.getStatus().getMessage()); } } catch (Exception e) { System.err.println("Exception while doing set: " + e.getMessage()); } // Print the value from synchronous get if (getObject != null) { System.out.println("Synchronous Get Suceeded: " + (String) getObject); } else { System.err.println("Synchronous Get failed"); } // Check to see if ayncGet succeeded try { if ((getObject = getOp.get()) != null) { System.out.println("Asynchronous Get Succeeded: " + getObject); } else { System.err.println("Asynchronous Get failed: " + getOp.getStatus().getMessage()); } } catch (Exception e) { System.err.println("Exception while doing Aynchronous Get: " + e.getMessage()); } // Check to see if our delete succeeded if (do_delete) { try { if (delOp.get().booleanValue()) { System.out.println("Delete Succeeded"); } else { System.err.println("Delete failed: " + delOp.getStatus().getMessage()); } } catch (Exception e) { System.err.println("Exception while doing delete: " + e.getMessage()); } } }}

Page 9: Couchbase Sdk Java 1.0

Getting Started

3

1. Enter the code in listing 1 into a file named Main.java

2. Download the couchbase-client and spymemcached client libraries for Java. You will also need the dependent JARfiles as well, as listed in the execution instructions below. One simple way to obtain the JAR and all dependencies isthrough the Maven repository.

3. Type the following commands:

$ javac -cp couchbase-client-1.0.0.jar:spymemcached-2.8.0.jar \ Main.java$ java -cp .:couchbase-client-1.0.0.jar:spymemcached-2.8.0.jar:\jettison-1.1.jar:netty-3.2.0.Final.jar:commons-codec-1.5.jar Main

Of course, substitute your own Couchbase server IP address. If you are on Linux or MacOS replace the semi-colon in thesecond command-line with a colon. The program will produce the following output:

2012-01-16 15:06:29.265 INFO com.couchbase.client.CouchbaseConnection: Added {QA sa=/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue2012-01-16 15:06:29.277 INFO com.couchbase.client.CouchbaseConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@1d3c468a2012-01-16 15:06:29.420 INFO com.couchbase.client.CouchbaseConnection: Shut down Couchbase clientSynchronous Get failedSet SucceededAsynchronous Get Succeeded: Hello World!

Much of this output is logging statements produced by the client library, to inform you of what's going on inside theclient library to help you diagnose issues. It says that a connection to Couchbase was added and that the connection statechanged. Then the code shows that the key spoon did not exist in Couchbase which is why the Synchronous Get failed.

Running the program again, within 10 seconds will produce the following output:

2012-01-16 15:37:12.242 INFO com.couchbase.client.CouchbaseConnection: Added {QA sa=/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue2012-01-16 15:37:12.253 INFO com.couchbase.client.CouchbaseConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@7f2ad19e2012-01-16 15:37:12.439 INFO com.couchbase.client.CouchbaseConnection: Shut down Couchbase clientSynchronous Get Succeeded: Hello World!Set SucceededAsynchronous Get Succeeded: Hello World!

Again you see the log statements, followed by the indication that this time, the key spoon was found in Couchbase withthe value "Hello World!" as evidenced in the Synchronous Get succeeding. Run the same piece of code after 10 seconds orset the do_delete flag to true and notice the changed behavior of the program. It is possible to get the precise message fromthe server in the case of a failure by calling the getOp.getStatus().getMessage() method on the Operation.

Congratulations, you've taken your first small step into a much larger world.

1.3. Couchbase API Overview

The Couchbase client library has many API methods that you can use to implement your distributed memory magic. Theclient library methods below are grouped into categories so that you'll have a quick reference you can refer to later.

Table 1.1. Synchronous Methods

decr Decrement a key and return the value.

get Gets a particular value from the cache.

getBulk Gets many values at the same time.

gets Gets a particular value with Check And Set support.

incr Increment the value of a key.

Table 1.2. Synchronous Check And Set

cas Perform a Check And Set operation.

Page 10: Couchbase Sdk Java 1.0

Getting Started

4

Table 1.3. Asynchronous Methods

add Adds an object to the cache if it does not exist already.

delete Deletes a value from the cache.

flush Clears the cache on all servers.

append Append to an existing value in the cache.

asyncCAS Check and set values of particular keys.

asyncDecr Decrement a value.

asyncGet Get a particular value.

asyncGetBulk Get many values at the same time.

asyncGets Get a value with CAS support.

asyncIncr Increment a value.

Table 1.4. Status Methods

addObserver Adds an observer to watch the connection status.

getAvailableServers Returns a list of, shocker, available servers.

getNodeLocator Returns a read only instance of the node locator.

getStats Returns connection statistics.

getTranscoder Returns the default transcoder instance.

getUnavailableServers Returns a list of the servers that are not available.

getVersions Returns the versions of all connected servers.

1.4. A More Substantial Program

Please download the Sample Code if you're interested in making a more substantial program that you can run. The pro-gram will create a user specified number of threads, that each try to create (or read from Couchbase) 100 random numbers.The code creates a CouchbaseClient object instance for each thread, and then proceeds to perform a gets() operationlooking for specific keys. The gets() operation will return null if the key has not been set. In this case the thread willcreate the value itself and set it into Couchbase and it will incur a 100 millisecond penalty for doing so. This simulates anexpensive database operation. You can find the full source code for the small application attached to the end of this article.

Let's discuss a few parts of the program, so you can understand the fundamentals of connecting to Couchbase servers, test-ing for the existence of particular key-value pairs, and setting a value to a key. These few operations will give you more ofan idea of how to begin.

Listing 2. Connecting to a set of Couchbase servers:

URI server = new URI(addresses);

ArrayList<URI> serverList = new ArrayList<URI>();

serverList.add(server); CouchbaseClient client = new CouchbaseClient( serverList, "default", "");

You can see, from these lines that you'll need to obtain an instance of a CouchbaseClient. There are numerous waysto construct one, but a constructor that is quite useful involved the ArrayList of URIs.

http://host-or-ip:port/pools

Page 11: Couchbase Sdk Java 1.0

Getting Started

5

The port you will be connecting to will be the port 8091 which is effectively a proxy that knows about all of the otherservers in the cluster and will provide quick protocol access. So in the case of this cluster, providing an addresses string asfollows, worked very well:

String addresses = "10.0.0.33:8091/pools"

Listing 3 is an abridged excerpt that shows the creation of an IntegerTranscoder, which is a useful class for converting ob-jects in Couchbase back to integers when needed. This is for convenience and reduces type casting. You can then see thata the gets() method is called. This returns a CASValue<T> of type integer which is useful for checking and setting a val-ue. If the value is null it means that Couchbase hasn't been given a value for this key. The code then sets a value. Other-wise, we can get its value and do something with it.

Listing 3. Check And Set operations

IntegerTranscoder intTranscoder = new IntegerTranscoder();

CASValue<Integer> value = client.gets(key, intTranscoder);

if (value == null) { // The value doesn't exist in Couchbase client.set(key, 15, rand.nextInt(), intTranscoder);

// Simulate the value taking time to create. Thread.sleep(100);

created++;

} else {

int v = value.getValue();

}

Setting values in Couchbase are done asynchronously, and the application does not have to wait for these to be complet-ed. Sometimes, though, you may want to ensure that Couchbase has been sent some values, and you can do this by callingclient.waitForQueues() and giving it a timeout for waiting for this to occur, as shown in Listing 4.

Listing 4. Waiting for the data to be set into Couchbase.

client.waitForQueues(1, TimeUnit.MINUTES);

1.5. How to Build and Run the Sample ApplicationDownload the entire Java Getting Started Source code and follow along with the steps.

You can compile and run the program using the following steps.

$ javac -cp couchbase-client-1.0.0.jar:spymemcached-2.8.0.jar \ GettingStarted.java$ java -cp .:couchbase-client-1.0.0.jar:\spymemcached-2.8.0.jar:jettison-1.1.jar:netty-3.2.0.Final.jar:\commons-codec-1.5.jar GettingStarted http://192.168.3.104:8091/pools 10

Running this program generates the following output the first time:

Client-2 took 37.2500 ms per key. Created 35. Retrieved 65 from cache.Client-3 took 37.7800 ms per key. Created 35. Retrieved 65 from cache.Client-4 took 37.7100 ms per key. Created 35. Retrieved 65 from cache.Client-0 took 37.8300 ms per key. Created 35. Retrieved 65 from cache.Client-1 took 37.8400 ms per key. Created 35. Retrieved 65 from cache.

Running the program a second time before 15 seconds elapses, produces this output instead:

Client-1 took 4.6700 ms per key. Created 0. Retrieved 100 from cache.Client-3 took 4.6000 ms per key. Created 0. Retrieved 100 from cache.Client-4 took 4.7500 ms per key. Created 0. Retrieved 100 from cache.Client-2 took 4.7900 ms per key. Created 0. Retrieved 100 from cache.Client-0 took 4.8400 ms per key. Created 0. Retrieved 100 from cache.

Page 12: Couchbase Sdk Java 1.0

Getting Started

6

There are a few things that are interesting about the output. In the first scenario, the five threads collaborate to produce thesequence of random numbers such that the average time per key is significantly less than 100ms. Each thread is creating35 numbers, but reading 65 from the cache.

In the second run, because the 15 second timeout has not elapsed yet, all of the random numbers were retrieved from thecache by all of the threads. Notice that reading these values from Couchbase only takes a few milliseconds.

The complete source code for this is below. You would run this with the command line arguments like below after ensur-ing that the client libraries are included in the classpath.

$ javac -cp couchbase-client-1.0.0.jar:spymemcached-2.8.0.jar \ GettingStarted.java$ java -cp .:couchbase-client-1.0.0.jar:\spymemcached-2.8.0.jar:jettison-1.1.jar:netty-3.2.0.Final.jar:\commons-codec-1.5.jar GettingStarted http://192.168.3.104:8091/pools 10

Page 13: Couchbase Sdk Java 1.0

Getting Started

7

import java.util.Random;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import java.util.ArrayList;

import java.net.URI;

import com.couchbase.client.CouchbaseClient;

import net.spy.memcached.CASValue;import net.spy.memcached.transcoders.IntegerTranscoder;

/** * Sets up a number of threads each cooperating to generate a set of random * numbers and illustrates the time savings that can be achieved by using * Couchbase. */public class GettingStarted {

static final int numIntegers = 100; static String addresses; static CountDownLatch countdown;

/** * @param args */ public static void main(String[] args) {

if (args.length < 2) { System.err.println("usage: addresses numthreads"); System.exit(1); }

addresses = args[0];

int numThreads = Integer.parseInt(args[1]);

countdown = new CountDownLatch(numThreads);

for (int i = 0; i < numThreads; i++) { Thread t = new Thread(new ClientThread(String.format( "Client-%d", i))); t.setName("Client Thread " + i); t.start(); }

try { countdown.await(); } catch (InterruptedException e) { }

System.exit(0); }

private static class ClientThread implements Runnable {

private String name;

public ClientThread(String name) { this.name = name; }

@Override public void run() {

try { URI server = new URI(addresses);

ArrayList<URI> serverList = new ArrayList<URI>();

serverList.add(server);

CouchbaseClient client = new CouchbaseClient( serverList, "rags", "changeit"); IntegerTranscoder intTranscoder = new IntegerTranscoder();

// Not really random, all threads // will have the same seed and sequence of // numbers. Random rand = new Random(1);

long startTime = System.currentTimeMillis();

int created = 0; int cached = 0;

for (int i = 0; i < numIntegers; i++) { String key = String.format("Value-%d", i);

CASValue<Integer> value = client.gets(key, intTranscoder);

if (value == null) { // The value doesn't exist in Membase client.set(key, 15, rand.nextInt(), intTranscoder);

// Simulate the value taking time to create. Thread.sleep(100);

created++;

} else {

// The value does exist, another thread // created it already so this thread doesn't // have to. int v = value.getValue();

// Check that the value is what we // expect it to be. if (v != rand.nextInt()) { System.err.println("No match."); } cached++; }

client.waitForQueues(1, TimeUnit.MINUTES); }

System.err.println(String.format( "%s took %.4f ms per key. Created %d." + " Retrieved %d from cache.", name, (System.currentTimeMillis() - startTime) / (double)numIntegers, created, cached));

} catch (Throwable ex) { ex.printStackTrace(); }

countdown.countDown(); } }}

Page 14: Couchbase Sdk Java 1.0

Getting Started

8

1.6. Conclusion

You now know how to obtain the Couchbase Java client libraries, and write small Java programs to connect with yourCouchbase cluster and interact with it. Congratulations, you will be able to save your servers from burning down, and im-press your users with the blazing fast response that your application will be able to achieve.

Page 15: Couchbase Sdk Java 1.0

9

Chapter 2. TutorialIn order to follow this tutorial the following need to be installed and functional.

• Java SE 6 (or higher) installed

• Couchbase server installed and running

• Client libraries installed and available in the classpath. Please refer to for installation of the client JAR files and the de-pendencies and for running them.

2.1. Installation1. Download the Java client libraries for Couchbase

2. Download the entire Java Tutorial Source code and follow along with the steps.

2.2. Building a Chat Room ApplicationYou will be writing a distributed chat room application, where a nearly unlimited number of people could potentially betalking at the same time. The previous statements made by other users will be remembered in memory for a certain peri-od of time, after which they will be forgotten. When a user first connects to the server they will be sent the entire transcriptof messages that have not timed out on the server, after which they will be able to participate anonymously in the ongoingconversation. At any point in the conversation, they may quit, by typing the word '/quit'. Implementing these requirementswill demonstrate a number of important API methods of the spymemcached driver talking to a Couchbase server, which isproviding the distributed storage capabilities.

Let's get started.

2.3. Connecting with the ServerThe driver library contains a number of different ways to connect to a Couchbase server. First, I will begin with a discus-sion of these methods and then we will use one of those methods to make the chat room client application connect withyour Couchbase installation.

There are more than one way of connecting with one or more Couchbase servers from the driver:

1. A direct connection can be made by creating an instance of the CouchbaseClient object and passing in one or more ad-dresses. For example:

URI server = new URI(addresses); ArrayList<URI> serverList = new ArrayList<URI>(); serverList.add(server); CouchbaseClient client = new CouchbaseClient( serverList, "default", "");

It's recommended to provide more than one server address of all the servers participating in the Couchbase cluster sincethe client can recover easily if the original server goes down.

2. Use the connection factory CouchbaseConnectionFactoryconstructors to establish a connection with your serv-er:

URI base = new URI(String.format( "http://%s:8091/pools", serverAddress)); ArrayList<URI> serverList = new ArrayList<URI>(); serverList.add(base); CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(serverList, "default", "");

Page 16: Couchbase Sdk Java 1.0

Tutorial

10

3. Create a connection that is authenticated using SASL by using a CouchbaseConnectionFactory. Merely spec-ifying the authenticated bucket will establish an authenticated connection. In the case of Couchbase, the username andpassword you use here are based on the buckets you have defined on the server. The username is the bucket name, andthe password is the password used when creating the bucket. I will talk more about this later, in the meantime here isthe code you will need to authenticate and start using a bucket with SASL authentication.

CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(baseURIs, "rags", "password"); client = new CouchbaseClient((CouchbaseConnectionFactory) cf);

Let's start making modifications to the tutorial Main.java class in order to make our first connection. Here we will bemaking an unauthenticated ASCII protocol connection to the server. After you have the tutorial code working, you caneasily go back and change the connect() method to use authentication.

First, modify main to read:

public static void main(String[] args) {

if (args.length != 1) { System.err.println("usage: serveraddress"); System.exit(1); }

String serverAddress = args[0];

System.out.println(String.format("Connecting to %s",serverAddress));

try {

connect(serverAddress); client.shutdown(1, TimeUnit.MINUTES);

} catch (IOException ex) { ex.printStackTrace(); }

}

Next, add the connect() method.

private void connect(String serverAddress) throws Exception {

URI base = new URI(String.format("http://%s:8091/pools",serverAddress)); List<URI> baseURIs = new ArrayList<URI>(); baseURIs.add(base); CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(baseURIs, "default", "");

client = new CouchbaseClient((CouchbaseConnectionFactory) cf);

You'll recognize this constructor as a single server connection. What if you want to know more about the current connec-tion state such as when the connection has been gained, or lost? You can add a connection observer by modifying the con-nect method and adding the following lines:

public void connectionLost(SocketAddress sa) { System.out.println("Connection lost to " + sa.toString()); }

public void connectionEstablished(SocketAddress sa, int reconnectCount) { System.out.println("Connection established with " + sa.toString()); System.out.println("Reconnected count: " + reconnectCount); } });

}

You've only connected with one server, what if it goes offline? This can easily be fixed by changing the first three lines ofthe connect method:

Page 17: Couchbase Sdk Java 1.0

Tutorial

11

URI fallback = new URI( String.format("http://%s:8091/pools",fallbackAddress)); baseURIs.add(fallback);

This class will even work with colon-delimited IPv6 addresses.

Finally, you need to create the static member variable to store the client instance at the top of the class:

private static CouchbaseClient client;

Now you can try compiling and running the application.

You can see that the driver outputs some logging statements indicating that it is making two connections. You can also seethat the connection observer you added to the connect() method is being called with the addresses of the two serversas they are connected and the reconnection count is 1 indicating that the network is in good shape. It's ready to get somework done.

2.4. Configuring Logging

If you want to configure the logging framework used at runtime you can use the following:

System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SunLogger");

or

System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.Log4JLogger");

The default logger simply logs everything to the standard error stream.

2.5. Shutting Down a Client Connection

The client application will remain running until the client.shutdown() or client.shutdown(long, TimeU-nit) methods are called.

The shutdown() method shuts the application down immediately and any outstanding work will be stopped.

The shutdown(long, TimeUnit) method will actually wait until any outstanding queued work is completed beforeshutting down, but it will time out in the given period of time. This would be the preferred method of shutting down theclient connection.

2.6. Increment and Decrement Operations

The API contains methods that are able to atomically increment a variable in the cache and decrement a variable. Effec-tively this means that these operations are safe for use by any client across the cluster at any time and there is some guar-antee that these will be done in the right order. We will demonstrate these methods by tracking the total number of chatclients connected to the server.

Add the following lines to the Main method after the connect method:

try { connect(serverAddress);

register(); unregister();

client.shutdown(1, TimeUnit.MINUTES);

} catch (IOException e) { e.printStackTrace();}

Page 18: Couchbase Sdk Java 1.0

Tutorial

12

Then add the following two methods to the end of the class:

private static boolean register() {

userId = client.incr("UserId", 1, 1); System.out.println("You are user " + userId + ".");

userCount = client.incr("UserCount", 1, 1); System.out.println("There are currently " + userCount + " connected.");

return true;}

private static void unregister() {

client.decr("UserCount", 1); System.out.println("Unregistered.");

}

These two methods demonstrate the use of the incr and decr methods which increment and decrement a variable, re-spectively. The application you are building uses this to keep track of how many users are currently running the program.This particular overload of the incr method takes a default value which it will use if the key UserCount does not exist, andwill return the current count. In this case the first user will be assigned user number 1. Finally, when the unregister methodis called, the decr method will be called to subtract 1 from the UserCount value.

Finally, you must add the following static member variables to the top of the class:

private static long userId = 0;private static long userCount = 0;

If you compile and run this program now, you will see the following output:

Reconnected count: -1You are user 1.Registration succeeded.There are currently 1 connected.Enter text, or /who to see user list, or /quit to exit.

Up to this point, the application is doing some very simple things, allowing a user to connect, and keeping track of howmany users and currently connected. It's time to start adding some data to the system, and providing some methods to in-teract between multiple clients.

2.7. Prepend and Append OperationsWe have implemented a client application that tracks how many clients are connected at the moment. Let's add the func-tionality to track the user numbers that are currently connected.

We'll nominate a key to keep a list of all of the user numbers that are currently connected, and then when a user discon-nects, remove their entry from the key. Right away, though, this presents a challenge. How can we guarantee that twousers starting at exactly the same time don't mess up the value by overwriting each other's edits? Let's find out.

The API contains a method called append. It takes a special value called a CAS, which stands for Check and Set, butwhere do we get this number? There is another method called gets which returns an object that can be asked for theCAS value we need to perform an append operation. Another interesting thing about the append method is that returns aFuture<Boolean> which means it is an asynchronous method. You can use the value it returns to wait for an answerindicating whether the operation succeeded or failed. Asynchronous methods also allow the code to do other things with-out having to wait for the result. At a later point in the code, the result of the operation can be obtained by using the futurevariable.

You will be using the append method in this tutorial, but the prepend method functions in exactly the same way ex-cept that append adds a string to the end of a value in the cache, and prepend puts a string at the front of a value in thecache.

Page 19: Couchbase Sdk Java 1.0

Tutorial

13

Both the append and prepend methods operate atomically, meaning they will perform the operation on a value in thecache and finish each operation before moving on to the next. You will not get interleaved appends and prepends. Ofcourse, the absolute order of these operations is not guaranteed.

The lines that are in bold-face should be changed in the register method of the code.

private static String getUserNameToken() { return String.format("<User-%d>", userId);}

private static boolean register() {

userId = client.incr("UserId", 1, 1); System.out.println("You are user " + userId + ".");

CASValue<Object> casValue = client.gets("CurrentUsers");

if (casValue == null) {

System.out.println("First user ever!");

try { client.set("CurrentUsers", Integer.MAX_VALUE, getUserNameToken()).get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }

} else {

Future<Boolean> appendDone = client.append(casValue.getCas(), "CurrentUsers", getUserNameToken());

try {

if (appendDone.get()) { System.out.println("Registration succeeded."); } else { System.out.println("Sorry registration failed."); return false; }

} catch (InterruptedException e) { e.printStackTrace(); return false; } catch (ExecutionException e) { e.printStackTrace(); return false; }

}

userCount = client.incr("UserCount", 1, 1); System.out.println("There are currently " + userCount + " connected.");

return true;}

First you can see that the client.gets("CurrentUsers") method is called to get a casValue. If that value isnull, it means that no one has ever connected, so that user is the first user. So we will simply set the value of Curren-tUsers using the new getUserNameToken() method.

Otherwise, we will append our userid to the list of users. To do this, we need to call the append method with the CASthat is in the casValue by calling its getCas() method. The append method is also asynchronous and returns aFuture<Boolean>. Calling the get() method on that future will return its value when its operation has been per-formed. The append operation can possibly fail, if for instance the size of the list of usernames exceeds the maximumsize of a value in the cache. So we handle both cases. If it returns true, we tell the user that the registration was a success.

Page 20: Couchbase Sdk Java 1.0

Tutorial

14

Otherwise the registration failed, so we'll tell the user this and return false to tell the main program that something wentwrong.

You need to modify the main method as well, to handle the possibility of the register method returning false.

try { connect(serverAddress);

if (register()) { unregister(); }

client.shutdown(1, TimeUnit.MINUTES);

} catch (IOException e) { e.printStackTrace();}

Now, we need to implement the cleanup of the user list when a user leaves. We will be modifying the unregistermethod to be very careful to remove the current userId from the CurrentUsers list before finishing. This is a potentiallydangerous operation for a distributed cache since two or more users may try to exit the application at the same time andmay try to replace the user list overwriting the previous changes. We will use a trick that effectively forces a distributedcritical section.

private static void unregister() {

try { // Wait for add to succeed. It will only // succeed if the value is not in the cache. while (!client.add("lock:CurrentUsers", 10, "1").get()) { System.out.println("Waiting for the lock..."); Thread.sleep(500); }

try { String oldValue = (String)client.get("CurrentUsers"); String userNameToken = getUserNameToken(); String newValue = oldValue.replaceAll(userNameToken, ""); client.set("CurrentUsers", Integer.MAX_VALUE, newValue); } finally { client.delete("lock:CurrentUsers"); }

} catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }

client.decr("UserCount", 1); System.out.println("Unregistered.");

}

Here we use the fact that the client.add() method will succeed if and only if a value does not exist for thegiven key to provide a way for only one application to be able to edit the CurrentUsers at a time. We will call thislock:CurrentUsers and it will expire in ten seconds. If we are not able to add, the code will sleep for 500 millisec-onds and try again.

The expiry time as defined in the protocol is documented as follows in the JavaDocs for the API:

Note

The actual value sent may either be Unix time (number of seconds since January 1, 1970, as a 32-bitvalue), or a number of seconds starting from current time. In the latter case, this number of secondsmay not exceed 60*60*24*30 (number of seconds in 30 days); if the number sent by a client is largerthan that, the server will consider it to be real Unix time value rather than an offset from current time.

Page 21: Couchbase Sdk Java 1.0

Tutorial

15

Once the add succeeds, a try/finally block is entered that actually gets the value of CurrentUsers and edits it, replacing thecurrent user token with the empty string. Then it sets it back. In the finally block, you can see that the lock is deleted usingthe client.delete() method. This will remove the key from Couchbase and allow any other clients that are waitingto unregister to continue into the critical section one at a time.

It is now time to complete the functionality of the tutorial application by writing a thread that will output the messages thatusers type as well as a method of getting input from the users.

First add the following member variable to the class:

private static Thread messageThread;

Next, modify the main method again to add the following lines in bold:

if (register()) { startMessageThread(); processInput(); unregister(); messageThread.interrupt();}

Now we will need to write a few helper methods, the first is:

private static void printMessages(long startId, long endId) {

for (long i = startId; i <= endId; i++) { String message = (String)client.get("Message:" + i); if (message != null) System.out.println(message); }

}

This method just iterates through a set of message numbers and prints the message to the screen. Couchbase does not al-low iteration of keys, but that's alright, we know exactly what pattern the key names follow, so we can do this.

The second method helps to find the oldest message that hasn't expired in the cache, starting at the last message and run-ning back toward the first message. Eventually it will find the first message and will return its number, considering that itwill have run one past the end, it needs to do a little fix-up to return the correct number.

private static long findFirstMessage(long currentId) { CASValue<Object> cas = null; long firstId = currentId; do { firstId -= 1; cas = client.gets("Message:" + firstId); } while (cas != null);

return firstId + 1;}

Finally we come to the method that prints out all of the messages as they come in. It's somewhat complicated so I'll de-scribe it in detail afterward.

Page 22: Couchbase Sdk Java 1.0

Tutorial

16

private static void startMessageThread() {

messageThread = new Thread(new Runnable() { public void run() {

long messageId = -1;

try { while (!Thread.interrupted()) {

CASValue<Object> msgCountCas = client.gets("Messages");

if (msgCountCas == null) { Thread.sleep(250); continue; }

long current = Long.parseLong((String)msgCountCas.getValue());

if (messageId == -1) { printMessages(findFirstMessage(current), current); } else if (current > messageId) { printMessages(messageId + 1, current); } else { Thread.sleep(250); continue; }

messageId = current;

}

} catch (InterruptedException ex) { } catch (RuntimeException ex) { }

System.out.println("Stopped message thread."); } });

messageThread.start();

}

This code creates a new thread of execution and assigns it to the messageThread variable. It creates an anonymousRunnable class that implements a run() method inline.

The messageId variable is set to a sentinel value so that we know when it is the first time through the while loop. Thewhile loop will iterate until the thread has been interrupted.

First, in the while loop, we write client.gets("Messages") which will return null if the value does notexist (in which case the loop sleeps for a little while and continues back to the top), or the method will return aCASValue<Object> instance that we can use to obtain the current message id.

If this is the first time through the loop (messageId == -1), we need to print out all of the messages since the first tothe current.

Otherwise if the current messageId is bigger than what we've previously seen, it means that some new messages havecome in since we last checked, so we will print them out.

Finally, nothing has changed since we last checked so just sleep some more.

At the end of the loop, we just make sure that the current message id is remembered for the next iteration of the loop. Ex-ceptions are handled by suppressing them, and if the while loop exits we'll print a message saying the message threadstopped.

At the end of the method, the thread is actually started.

Page 23: Couchbase Sdk Java 1.0

Tutorial

17

Great, so, now if messages come in, we'll display them. Also, when we first start the application, all of the messagesstored in the cache will be displayed. We need to implement the actual method that allows the user to interact with thecache.

private static void processInput() { boolean quit = false;

System.out.println("Enter text, or /who to see user list, or /quit to exit.");

do { String input = System.console().readLine(); if (input.startsWith("/quit")) { quit = true; } else if (input.startsWith("/who")) { System.out.println("Users connected: " + client.get("CurrentUsers")); } else { // Send a new message to the chat long messageId = client.incr("Messages", 1, 1); client.set("Message:" + messageId, 3600, getUserNameToken() + ": " + input); }

} while (!quit);

}

The method keeps track of a quit variable to know when to exit the do/while loop, then prints out some simple instructionsfor the user.

The console is read one line at a time, and each is checked to see if it starts with a command. If the user has typed '/quit'the quit flag will be set, and the loop will exit.

If the user has typed '/who' the CurrentUsers cached value will be output to the screen, so that at any time a user can checkwho is currently online.

Otherwise, the line is treated as a message. Here we increment the Messages key and use that value as a message id. Thenthe client.set() method is called with a key of Message:MessageId with a timeout of one hour, followed by theuser's name and the text that they entered.

These changes to the cache will be noticed by the message thread, and output to the screen. Of course this means that eachuser will see his or her messages repeated back to them.

If you compile and run the program in multiple terminal windows, you can talk to yourself. This is about as fun as thingscan get, isn't it? Notice how intelligent you can be.

2.8. Using Buckets

Up to this point, the test application has been using the default bucket. This is because it is not authenticated. The defaultbucket on Couchbase can be useful when you first start out, but as you build more complex applications, you may wantto partition your data into different buckets to improve fault tolerance by boosting replication or just so that one bucketcan be cleared without affecting all of the data you have cached in other buckets. You may also want to partition your keyspace among several applications to avoid naming collisions.

Page 24: Couchbase Sdk Java 1.0

Tutorial

18

Figure 2.1. Figure 1: Creating a private bucket.

Figure 1 shows the dialog in the Couchbase Web Console that demonstrates creating a new bucket called private withtwo replicas. Here you also choose a password to protect the bucket during SASL authentication. How do you accessthis bucket? You have already learned about how to make a SASL authenticated connection to Couchbase, if you use thebucket name as the username, and the password you provided when creating the bucket, you will connect to the privatebucket for data storage. The following code would accomplish this:

// We have used private as the username and private as the password// but you would not do this, you would be much smarter and use// something much harder to guess. CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(baseURIs, "private", "private"); client = new CouchbaseClient((CouchbaseConnectionFactory) cf);

Page 25: Couchbase Sdk Java 1.0

Tutorial

19

2.9. Error Handling

At this point, you may still be wondering how CAS values are used to prevent clients from writing over values that werechanged by another client.

Note

In essence, the CAS value exists so that that a client can 'hold' the CAS value for a item ID that itknows, and only update the item if the CAS has not changed. Hence, Check And Set (CAS). In amulti-client environment it's designed to prevent one client changing the value of an item when an-other client may have already updated it.

Unfortunately there's no way to lock items; individual operations (set, for example) are atomic, but multiple operations arenot, and this is what CAS is designed to protect against. To stop you changing a value that has changed since the last GET.

In order to demonstrate this situation, add the bold lines to the processInput method to allow a way to perform a CASoperation and see what happens if two of these operations is interleaved if two copies of the program are run at the sametime.

} else if (input.startsWith("/who")) { System.out.println("Users connected: " + client.get("CurrentUsers"));} else if (input.startsWith("/cas")) { runCasTest();} else {

Now create the runCasTest() method at the bottom of the class:

private static void runCasTest() {

System.out.println("Testing a CAS operation."); CASValue<Object> cas = client.gets("CasTest");

if (cas == null) { // Must create it first System.out.println("Creating CasTest value."); client.set("CasTest", 120, "InitialValue"); return; }

System.out.println("CAS for CasTest = "+cas.getCas()); System.out.println("Sleeping for 10 seconds."); try { Thread.sleep(10000); } catch (InterruptedException e) { }

CASResponse response = client.cas("CasTest", cas.getCas(), "ReplacedValue"); if (response.equals(CASResponse.OK)) { System.out.println("OK response."); } else if (response.equals(CASResponse.EXISTS)) { System.out.println("EXISTS response."); } else if (response.equals(CASResponse.NOT_FOUND)) { System.out.println("NOT_FOUND response."); }

cas = client.gets("CasTest"); System.err.println("CAS after = "+cas.getCas());}

The first time the test is run (by typing "/cas" while the application is running) the gets() method will returnnull so it will just set the CasTest key to "InitialValue" and return. The second time the test is run it will get aCASValue<Object> instance from the gets() method, print out its value, and then sleep for 10 seconds. Then aftersleeping the code performs a client.cas() method call to replace the value.

Page 26: Couchbase Sdk Java 1.0

Tutorial

20

If you run this in two different windows you may see output something like the following if you time things just right:

/cas/casTesting a CAS operation.CAS for CasTest = 2637312854241Sleeping for 10 seconds.OK response.CAS after = 2850841875395

In the second copy of the application, the output would look something like this:

Testing a CAS operation.CAS for CasTest = 2637312854241Sleeping for 10 seconds.EXISTS response.CAS after = 2850841875395

What you see is that when the CAS is 2637312854241, the second client modifies the value before the first client is donesleeping. Instead of getting an OK response, that client gets an EXISTS response indicating that a change has been madebefore it had a chance to do so, so its client.cas() operation failed, and the code would have to handle this situationto rectify the situation.

Locking is not an option if you want to have an operational distributed cache. Locking causes contention and complexity.Being able to quickly detect when a value has been overwritten without having to hold a lock is a simple solution to theproblem. You will be able to write code to handle the situation either by returning an error to the user, or retrying the oper-ation after obtaining another CAS value.

2.10. Using vbuckets

One of the newest features of the couchbase-client and spymmecached libraries is called vbucket support. The vBucket al-gorithm allows Couchbase to automatically connect clients to the data they need even if servers are being rearranged, tak-en offline, and so on. It is an indirection layer on top of buckets in Couchbase that are transparent to clients. According toan article written by Dustin Sallings the basic requirements that led to the development of vbuckets are as follows:

1. Never service a request on the wrong server.

2. Allow scaling up and down at will.

3. Servers refuse commands that they should not service, but

4. Servers still do not know about each other.

5. We can hand data sets from one server another atomically, but

6. There are no temporal constraints.

7. Consistency is guaranteed.

8. Absolutely no network overhead is introduced in the normal case.

If you want to know more about vbuckets I encourage you to read through Dustin's article. I just wanted to spend sometime explaining how to modify the tutorial application to connect using vbuckets.

All you need to start using this functionality is to use a new Couchbase constructor that allows you to pass in a list ofbase URIs, and the bucket name and password as we did in the connect() method earlier.

Page 27: Couchbase Sdk Java 1.0

Tutorial

21

try { URI server = new URI(addresses); ArrayList<URI> serverList = new ArrayList<URI>(); serverList.add(server); CouchbaseClient client = new CouchbaseClient( serverList, "rags", "password"); } catch (Throwable ex) { ex.printStackTrace(); }

Compile and run the application:

$ javac -cp couchbase-client-1.0.0.jar:spymemcached-2.8.0.jar Tutorial.java$ java -cp .:couchbase-client-1.0.0.jar:\spymemcached-2.8.0.jar:jettison-1.1.jar:netty-3.2.0.Final.jar:\commons-codec-1.5.jar Tutorial 192.168.3.104

Replace serverhost with the name or IP address of your server, you won't need the port this time. You will see somethinglike the following output:

Jan 17, 2012 12:11:43 PM net.spy.memcached.MemcachedConnection createConnectionsINFO: Added {QA sa=/192.168.3.111:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queueJan 17, 2012 12:11:43 PM net.spy.memcached.MemcachedConnection handleIOINFO: Connection state changed for sun.nio.ch.SelectionKeyImpl@2abe0e27Jan 17, 2012 12:11:43 PM net.spy.memcached.auth.AuthThread$1 receivedStatusINFO: Authenticated to /192.168.3.111:11210

You can see that it connects to the server and automatically loads the list of all Couchbase servers, connects to them andauthenticates. It uses the vbucket algorithm automatically, and no code changes to the application will be required.

2.11. The Tutorial Example Code

The Complete code for the tutorial is below and you would compile and run it with the command line arguments as belowensuring that the client libraries are included in the Java classpath.

$ javac -cp couchbase-client-1.0.0.jar:spymemcached-2.8.0.jar Tutorial.java$ java -cp .:couchbase-client-1.0.0.jar:\spymemcached-2.8.0.jar:jettison-1.1.jar:netty-3.2.0.Final.jar:\commons-codec-1.5.jar Tutorial 192.168.3.104

Page 28: Couchbase Sdk Java 1.0

Tutorial

22

import java.io.IOException;import java.net.SocketAddress;import java.net.URI;import java.net.URISyntaxException;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;

import javax.naming.ConfigurationException;

import net.spy.memcached.CASMutation;import net.spy.memcached.CASMutator;import net.spy.memcached.CASResponse;import net.spy.memcached.CASValue;import net.spy.memcached.CachedData;import net.spy.memcached.ConnectionObserver;import net.spy.memcached.transcoders.SerializingTranscoder;import net.spy.memcached.transcoders.Transcoder;

import com.couchbase.client.CouchbaseClient;import com.couchbase.client.CouchbaseConnectionFactory;

public class Tutorial {

private static CouchbaseClient client; private long userId = 0; private long userCount = 0; private Thread messageThread;

/** * Main Program for a Couchbase chat room application using * the couchbase-client and spymemcached libraries. */ public static void main(String[] args) {

if (args.length != 1) { System.err.println("usage: serveraddresses"); System.exit(1); }

try {

new Tutorial().run(args[0]);

} catch (Exception ex) { System.err.println(ex); client.shutdown(); } }

public void run(String serverAddress) throws Exception {

System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SunLogger");

System.out.println(String .format("Connecting to %s", serverAddress));

connect(serverAddress);

if (register()) { startMessageThread(); Runtime.getRuntime().addShutdownHook(new unregisterThread()); processInput(); unregister(); messageThread.interrupt(); } client.shutdown(1, TimeUnit.MINUTES); System.exit(0); }

/** * Connect to the server, or servers given. * @param serverAddress the server addresses to connect with. * @throws IOException if there is a problem with connecting. * @throws URISyntaxException * @throws ConfigurationException */ private void connect(String serverAddress) throws Exception {

URI base = new URI( String.format("http://%s:8091/pools",serverAddress)); List<URI> baseURIs = new ArrayList<URI>(); baseURIs.add(base); CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(baseURIs, "rags", "changeit");

client = new CouchbaseClient((CouchbaseConnectionFactory) cf);

client.addObserver(new ConnectionObserver() {

public void connectionLost(SocketAddress sa) { System.out.println("Connection lost to " + sa.toString()); }

public void connectionEstablished(SocketAddress sa, int reconnectCount) { System.out.println("Connection established with " + sa.toString()); System.out.println("Reconnected count: " + reconnectCount); } });

}

/** * Get a user name token for the current user. * @return the token to use. */ private String getUserNameToken() { return String.format("<User-%d>", userId); }

/** * Register the user with the chat room. * @return true if the registration succeeded, false otherwise. */ private boolean register() throws Exception {

userId = client.incr("UserId", 1, 1); System.out.println("You are user " + userId + ".");

CASValue<Object> casValue = client.gets("CurrentUsers");

if (casValue == null) {

System.out.println("First user ever!");

client.set("CurrentUsers", Integer.MAX_VALUE, getUserNameToken()).get();

} else {

Future<Boolean> appendDone = client.append(casValue.getCas(), "CurrentUsers", getUserNameToken());

if (appendDone.get()) { System.out.println("Registration succeeded."); } else { System.out.println("Sorry registration failed."); return false; }

}

userCount = client.incr("UserCount", 1, 1); System.out.println("There are currently " + userCount + " connected.");

return true; }

/** * A Transcoder for strings that just delegates to using * a SerializingTranscoder. */ class StringTranscoder implements Transcoder<String> {

final SerializingTranscoder delegate = new SerializingTranscoder();

public boolean asyncDecode(CachedData d) { return delegate.asyncDecode(d); }

public String decode(CachedData d) { return (String)delegate.decode(d); }

public CachedData encode(String o) { return delegate.encode(o); }

public int getMaxSize() { return delegate.getMaxSize(); }

}

/** * Unregister the current user from the chat room. */ private void unregister() throws Exception {

CASMutation<String> mutation = new CASMutation<String>() { public String getNewValue(String current) { return current.replaceAll(getUserNameToken(), ""); } };

Transcoder<String> transcoder = new StringTranscoder(); CASMutator<String> mutator = new CASMutator<String>(client, transcoder); mutator.cas("CurrentUsers", "", 0, mutation);

client.decr("UserCount", 1); System.out.println("Unregistered.");

}

/** * Print a number of messages. * @param startId the first message id to output. * @param endId the last message id to output. */ private void printMessages(long startId, long endId) {

for (long i = startId; i <= endId; i++) { String message = (String)client.get("Message:" + i); if (message != null) System.out.println(message); }

}

/** * Finds the first message id that has not yet expired. * @param currentId the last message id to start with. * @return the first message id known in the system at the time. */ private long findFirstMessage(long currentId) { CASValue<Object> cas = null; long firstId = currentId; do { firstId -= 1; cas = client.gets("Message:" + firstId); } while (cas != null);

return firstId + 1; }

/** * Start up the message display thread. */ private void startMessageThread() {

messageThread = new Thread(new Runnable() { public void run() {

long messageId = -1;

try { while (!Thread.interrupted()) {

CASValue<Object> msgCountCas = client .gets("Messages");

if (msgCountCas == null) { Thread.sleep(250); continue; }

long current = Long.parseLong((String)msgCountCas .getValue());

if (messageId == -1) { printMessages(findFirstMessage(current), current); } else if (current > messageId) { printMessages(messageId + 1, current); } else { Thread.sleep(250); continue; }

messageId = current;

}

} catch (InterruptedException ex) { } catch (RuntimeException ex) { }

System.out.println("Stopped message thread."); } });

messageThread.start(); }

/** * Handle shutdown by unregistering */ private class unregisterThread extends Thread {

public void run() { try {

unregister(); messageThread.interrupt(); client.shutdown(1, TimeUnit.MINUTES); super.run();; } catch (Exception e) { } } }

/** * Processes input from the user, and sends messages to the virtual * chat room. */ private void processInput() { boolean quit = false;

System.out. println("Enter text, or /who to see user list, or /quit to exit.");

try { do { String input = System.console().readLine(); System.out.println(input); if (input.startsWith("/quit")) { quit = true; } else if (input.startsWith("/who")) { System.out.println("Users connected: " + client.get("CurrentUsers")); } else if (input.startsWith("/cas")) { runCasTest(); } else { // Send a new message to the chat long messageId = client.incr("Messages", 1, 1); client.set("Message:" + messageId, 3600, getUserNameToken() + ": " + input); }

} while (!quit); } catch (Exception e) { }

}

private void runCasTest() { System.out.println("Testing a CAS operation."); CASValue<Object> cas = client.gets("CasTest");

if (cas == null) { // Must create it first System.out.println("Creating CasTest value."); client.set("CasTest", 120, "InitialValue"); return; }

System.out.println("CAS for CasTest = "+cas.getCas()); System.out.println("Sleeping for 10 seconds."); try { Thread.sleep(10000); } catch (InterruptedException e) { }

CASResponse response = client.cas("CasTest", cas.getCas(), "ReplacedValue"); if (response.equals(CASResponse.OK)) { System.out.println("OK response."); } else if (response.equals(CASResponse.EXISTS)) { System.out.println("EXISTS response."); } else if (response.equals(CASResponse.NOT_FOUND)) { System.out.println("NOT_FOUND response."); }

cas = client.gets("CasTest"); System.err.println("CAS after = "+cas.getCas()); }}

Page 29: Couchbase Sdk Java 1.0

Tutorial

23

Congratulations, you have completed the Couchbase portion of this tutorial. You can download the entire Java TutorialSource code and follow along with the steps.

Page 30: Couchbase Sdk Java 1.0

24

Chapter 3. Using the APIs

The Client libraries provides an interface to both Couchbase and Memcached clients using a consistent interface. The in-terface between your Java application and your Couchbase or Memcached servers is provided through the instantiation ofa single object class, CouchbaseClient.

Creating a new object based on this class opens the connection to each configured server and handles all the communica-tion with the server(s) when setting, retrieving and updating values. A number of different methods are available for creat-ing the object specifying the connection address and methods.

3.1. Connecting to a Couchbase Bucket

You can connect to specific Couchbase buckets (in place of using the default bucket, or a hostname/port combinationconfigured on the Couchbase cluster) by using the Couchbase URI for one or more Couchbase nodes, and specifying thebucket name and password (if required) when creating the new CouchbaseClient object.

For example, to connect to the local host and the default bucket:

List<URI> uris = new LinkedList<URI>();

uris.add(URI.create("http://127.0.0.1:8091/pools")); try { client = new CouchbaseClient(uris, "default", ""); } catch (Exception e) { System.err.println("Error connecting to Couchbase: " + e.getMessage()); System.exit(0); }

The format of this constructor is:

CouchbaseClient(URIs,BUCKETNAME,BUCKETPASSWORD)

Where:

• URIS is a List of URIs to the Couchbase nodes. The format of the URI is the hostname, port and path /pools.

• BUCKETNAME is the name of the bucket on the cluster that you want to use. Specified as a String.

• BUCKETPASSWORD is the password for this bucket. Specified as a String.

The returned CouchbaseClient object can be used as with any other CouchbaseClient object.

3.2. Connecting using Hostname and Port with SASL

If you want to use SASL to provide secure connectivity to your Couchbase server then you could create a CouchbaseC-onnectionFactory that defines the SASL connection type, userbucket and password.

The connection to Couchbase uses the underlying protocol for SASL. This is similar to the earlier example except that weuse the CouchbaseConnectionFactory.

List<URI> baseURIs = new ArrayList<URI>(); baseURIs.add(base); CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(baseURIs, "userbucket", "password");

client = new CouchbaseClient((CouchbaseConnectionFactory) cf);

Page 31: Couchbase Sdk Java 1.0

Using the APIs

25

3.3. Shutting down the Connection

The preferred method for closing a connection is to cleanly shutdown the active connection with a timeout using theshutdown() method with an optional timeout period and unit specification. The following will shutdown the activeconnection to all the configured servers after 60 seconds:

client.shutdown(60, TimeUnit.SECONDS);

The unit specification relies on the TimeUnit object enumerator, which supports the following values:

Constant Description

TimeUnit.NANOSECONDS Nanoseconds (10 -9 s).

TimeUnit.MICROSECONDS Microseconds (10 -6 s).

TimeUnit.MILLISECONDS Milliseconds (10 -3 s).

TimeUnit.SECONDS Seconds.

The method returns a boolean value indicating whether the shutdown request completed successfully.

You also can shutdown an active connection immediately by using the shutdown() method to your Memcached objectinstance. For example:

client.shutdown();

In this form the shutdown() method returns no value.

Page 32: Couchbase Sdk Java 1.0

26

Chapter 4. Java Method SummaryThe couchbase-client and spymemcached libraries support the full suite of API calls to Couchbase. A summaryof the supported methods are listed in Table 4.1, “Java Client Library Method Summary”.

Table 4.1. Java Client Library Method Summary

Method Title

client.add(key, expiry, value) Add a value with the specified key that does not already ex-ist

client.add(key, expiry, value,transcoder)

Add a value that does not already exist using customtranscoder

client.append(casunique, key, value) Append a value to an existing key

client.append(casunique, key, value,transcoder)

Append a value to an existing key

client.asyncCAS(key, casunique, value) Asynchronously compare and set a value

client.asyncCAS(key, casunique, expiry,value, transcoder)

Asynchronously compare and set a value with customtranscoder and expiry

client.asyncCAS(key, casunique, value,transcoder)

Asynchronously compare and set a value with customtranscoder

client.asyncDecr(key, offset) Asynchronously decrement the value of an existing key

client.asyncGetAndTouch(key, expiry) Asynchronously get a value and update the expiration timefor a given key

client.asyncGetAndTouch(key, expiry,transcoder)

Asynchronously get a value and update the expiration timefor a given key using a custom transcoder

client.asyncGet(key) Asynchronously get a single key

client.asyncGetBulk(keycollection) Asynchronously get multiple keys

client.asyncGetBulk(keyn) Asynchronously get multiple keys

client.asyncGetBulk(transcoder, keyn) Asynchronously get multiple keys using a customtranscoder

client.asyncGetBulk(keycollection,transcoder)

Asynchronously get multiple keys using a customtranscoder

client.asyncGet(key, transcoder) Asynchronously get a single key using a custom transcoder

client.asyncGets(key) Asynchronously get single key value with CAS value

client.asyncGets(key, transcoder) Asynchronously get single key value with CAS value usingcustom transcoder

client.asyncIncr(key, offset) Asynchronously increment the value of an existing key

client.cas(key, casunique, value) Compare and set

client.cas(key, casunique, expiry, val-ue, transcoder)

Compare and set with a custom transcoder and expiry

client.cas(key, casunique, value,transcoder)

Compare and set with a custom transcoder

client.decr(key, offset) Decrement the value of an existing numeric key

client.decr(key, offset, default) Decrement the value of an existing numeric key

Page 33: Couchbase Sdk Java 1.0

Java Method Summary

27

Method Title

client.decr(key, offset, default, ex-piry)

Decrement the value of an existing numeric key

client.delete(key) Delete the specified key

client.getAndTouch(key, expiry) Get a value and update the expiration time for a given key

client.getAndTouch(key, expiry,transcoder)

Get a value and update the expiration time for a given keyusing a custom transcoder

client.get(key) Get a single key

client.getBulk(keycollection) Get multiple keys

client.getBulk(keyn) Get multiple keys

client.getBulk(transcoder, keyn) Get multiple keys using a custom transcoder

client.getBulk(keycollection,transcoder)

Get multiple keys using a custom transcoder

client.get(key, transcoder) Get a single key using a custom transcoder

client.gets(key) Get single key value with CAS value

client.gets(key, transcoder) Get single key value with CAS value using customtranscoder

client.getStats() Get the statistics from all connections

client.getStats(statname) Get the statistics from all connections

client.incr(key, offset) Increment the value of an existing numeric key

client.incr(key, offset, default) Increment the value of an existing numeric key

client.incr(key, offset, default, ex-piry)

Increment the value of an existing numeric key

client.prepend(casunique, key, value) Prepend a value to an existing key using the defaulttranscoder

client.prepend(casunique, key, value,transcoder)

Prepend a value to an existing key using a customtranscoder

client.replace(key, value, expiry) Update an existing key with a new value

client.replace(key, value, expiry,transcoder)

Update an existing key with a new value using a customtranscoder

client.set(key, expiry, value) Store a value using the specified key

client.set(key, expiry, value,transcoder)

Store a value using the specified key

client.touch(key, expiry) Update the expiry time of an item

4.1. Synchronous Method Calls

The Java Client Libraries support the core Couchbase API methods as direct calls to the Couchbase server through the APIcall. These direct methods can be used to provide instant storage, retrieval and updating of Couchbase key/value pairs.

For example, the following fragment stores and retrieves a single key/value pair:

client.set("someKey", 3600, someObject);

Object myObject = client.get("someKey");

Page 34: Couchbase Sdk Java 1.0

Java Method Summary

28

In the example code above, the client get() call will wait until a response has been received from the appropriatelyconfigured Couchbase servers before returning the required value or an exception.

4.2. Asynchronous Method CallsIn addition, the librares also support a range of asynchronous methods that can be used to store, update and retrieve valueswithout having to explicitly wait for a response.

The asynchronous methods use a Future object or its appropriate implementation which is returned by the initial methodcall for the operation. The communication with the Couchbase server will be handled by the client libraries in the back-ground so that the main program loop can continue. You can recover the status of the operation by using a method tocheck the status on the returned Future object. For example, rather than synchronously getting a key, an asynchronous callmight look like this:

GetFuture getOp = client.asyncGet("someKey");

This will populate the Future object GetFuture with the response from the server. The Future object class is definedhere. The primary methods are:

• cancel()

Attempts to Cancel the operation if the operation has not already been completed.

• get()

Waits for the operation to complete. Gets the object returned by the operation as if the method was synchronous ratherthan asynchronous.

• get(timeout, TimeUnit)

Gets the object waiting for a maximum time specified by timeout and the corresponding TimeUnit.

• isDone()

The operation has been completed successfully.

For example, you can use the timeout method to obtain the value or cancel the operation:

GetFuture getOp = client.asyncGet("someKey");

Object myObj;

try { myObj = getOp.get(5, TimeUnit.SECONDS);} catch(TimeoutException e) { getOp.cancel(false);}

Alternatively, you can do a blocking wait for the response by using the get() method:

Object myObj;

myObj = getOp.get();

4.3. Object Serialization (Transcoding)All of the Java client library methods use the default Whalin transcoder that provides compatilibility with memcachedclients for the serialization of objects from the object type into a byte array used for storage within Couchbase.

You can also use a custom transcoder the serialization of objects. This can be to serialize objects in a format that is com-patible with other languages or environments.

Page 35: Couchbase Sdk Java 1.0

Java Method Summary

29

You can customize the transcoder by implementing a new Transcoder interface and then using this when storing and re-trieving values. The Transcoder will be used to encode and decode objects into binary strings. All of the methods thatstore, retrieve or update information have a version that supports a custom transcoder.

4.4. Expiry Values

All values in Couchbase and Memcached can be set with an expiry value. The expiry value indicates when the item shouldbe expired from the database and can be set when an item is added or updated.

Within spymemcached the expiry value is expressed in the native form of an integer as per the Memcached protocolspecification. The integer value is expressed as the number of seconds, but the interpretation of the value is different basedon the value itself:

• Expiry is less than 30*24*60*60 (30 days)

The value is interpreted as the number of seconds from the point of storage or update.

• Expiry is greater than 30*24*60*60

The value is interpreted as the number of seconds from the epoch (January 1st, 1970).

• Expiry is 0

This disables expiry for the item.

For example:

client.set("someKey", 3600, someObject);

The value will have an expiry time of 3600 seconds (one hour) from the time the item was stored.

The statement:

client.set("someKey", 1307458800, someObject);

Will set the expiry time as June 7th 2011, 15:00 (UTC).

Page 36: Couchbase Sdk Java 1.0

30

Chapter 5. Store OperationsThe Couchbase Java Client Library store operations set information within the Couchbase database. These are distinctfrom the update operations in that the key does not have to exist within the Couchbase database before being stored.

Table 5.1. Java Client Library Store Methods

Method Title

client.add(key, expiry, value) Add a value with the specified key that does not already ex-ist

client.add(key, expiry, value,transcoder)

Add a value that does not already exist using customtranscoder

client.replace(key, value, expiry) Update an existing key with a new value

client.replace(key, value, expiry,transcoder)

Update an existing key with a new value using a customtranscoder

client.set(key, expiry, value) Store a value using the specified key

client.set(key, expiry, value,transcoder)

Store a value using the specified key

5.1. Add OperationsThe add() method adds a value to the database with the specified key, but will fail if the key already exists in the data-base.

API Call client.add(key, expiry, value)

Description Add a value with the specified key that does not already exist

Returns Future<Boolean> (Future value as Boolean)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Object value Value to be stored

The add() method adds a value to the database using the specified key.

client.add("someKey", 0, someObject);

Unlike Section 5.2, “Set Operations” the operation can fail (and return false) if the specified key already exist.

For example, the first operation in the example below may complete if the key does not already exist, but the second oper-ation will always fail as the first operation will have set the key:

OperationFuture<Boolean> addOp = client.add("someKey",0,"astring");System.out.printf("Result was %b",addOp.get());addOp = client.add("someKey",0,"anotherstring");System.out.printf("Result was %b",addOp.get());

API Call client.add(key, expiry, value, transcoder)

Description Add a value with the specified key that does not already exist

Page 37: Couchbase Sdk Java 1.0

Store Operations

31

Returns Future<Boolean> (Future value as Boolean)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

This method is identical to the add() method, but supports the use of a custom transcoder for serialization of the objectvalue. For more information on transcoding, see Section 4.3, “Object Serialization (Transcoding)”.

5.2. Set Operations

The set operations store a value into Couchbase or Memcached using the specified key and value. The value is storedagainst the specified key, even if the key already exists and has data. This operation overwrites the existing with the newdata.

API Call client.set(key, expiry, value)

Description Store a value using the specified key, whether the key already exists or not

Returns Object (Binary object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Object value Value to be stored

The first form of the set() method stores the key, sets the expiry (use 0 for no expiry), and the corresponding object val-ue using the built in transcoder for serialization.

The simplest form of the command is:

client.set("someKey", 3600, someObject);

The Boolean return value will be true if the value was stored. For example:

OperationFuture<Boolean> setOp = membase.set("someKey",0,"astring");System.out.printf("Result was %b",setOp.get());

API Call client.set(key, expiry, value, transcoder)

Description Store a value using the specified key, whether the key already exists or not

Returns Object (Binary object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Page 38: Couchbase Sdk Java 1.0

Store Operations

32

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

This method is identical to the set() method, but supports the use of a custom transcoder for serialization of the objectvalue. For more information on transcoding, see Section 4.3, “Object Serialization (Transcoding)”.

Page 39: Couchbase Sdk Java 1.0

33

Chapter 6. Retrieve OperationsThe retrieve operations get information from the Couchbase database. A summary of the available API calls is listed be-low.

Table 6.1. Java Client Library Retrieval Methods

Method Title

client.asyncGetAndTouch(key, expiry) Asynchronously get a value and update the expiration timefor a given key

client.asyncGetAndTouch(key, expiry,transcoder)

Asynchronously get a value and update the expiration timefor a given key using a custom transcoder

client.asyncGet(key) Asynchronously get a single key

client.asyncGetBulk(keycollection) Asynchronously get multiple keys

client.asyncGetBulk(keyn) Asynchronously get multiple keys

client.asyncGetBulk(transcoder, keyn) Asynchronously get multiple keys using a customtranscoder

client.asyncGetBulk(keycollection,transcoder)

Asynchronously get multiple keys using a customtranscoder

client.asyncGet(key, transcoder) Asynchronously get a single key using a custom transcoder

client.asyncGets(key) Asynchronously get single key value with CAS value

client.asyncGets(key, transcoder) Asynchronously get single key value with CAS value usingcustom transcoder

client.getAndTouch(key, expiry) Get a value and update the expiration time for a given key

client.getAndTouch(key, expiry,transcoder)

Get a value and update the expiration time for a given keyusing a custom transcoder

client.get(key) Get a single key

client.getBulk(keycollection) Get multiple keys

client.getBulk(keyn) Get multiple keys

client.getBulk(transcoder, keyn) Get multiple keys using a custom transcoder

client.getBulk(keycollection,transcoder)

Get multiple keys using a custom transcoder

client.get(key, transcoder) Get a single key using a custom transcoder

client.gets(key) Get single key value with CAS value

client.gets(key, transcoder) Get single key value with CAS value using customtranscoder

6.1. Synchronous get MethodsThe synchronous get() methods allow for direct access to a given key/value pair.

API Call client.get(key)

Description Get one or more key values

Returns Object (Binary object)

Arguments

Page 40: Couchbase Sdk Java 1.0

Retrieve Operations

34

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

The get() method obtains an object stored in Couchbase using the default transcoder for serialization of the object.

For example:

Object myObject = client.get("someKey");

Transcoding of the object assumes the default transcoder was used when the value was stored. The returned object can beof any type.

If the request key does no existing in the database then the returned value is null.

API Call client.get(key, transcoder)

Description Get one or more key values

Returns T (Transcoded object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the get() retrieves a value from Couchbase using a custom transcoder.

For example to obtain an integer value using the IntegerTranscoder:

Transcoder<Integer> tc = new IntegerTranscoder();Integer ic = client.get("someKey", tc);

6.2. Asynchronous get MethodsThe asynchronous asyncGet() methods allow to retrieve a given value for a key without waiting actively for a re-sponse.

API Call client.asyncGet(key)

Description Get one or more key values

Returns Future<Object> (Future value as Object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Exceptions

TimeoutException Value could not be retrieved

The first form of the asyncGet() method obtains a value for a given key returning a Future object so that the value canbe later retrieved. For example, to get a key with a stored String value:

GetFuture<Object> getOp = client.asyncGet("samplekey");

String username;

try { username = (String) getOp.get(5, TimeUnit.SECONDS);} catch(Exception e) { getOp.cancel(false);}

Page 41: Couchbase Sdk Java 1.0

Retrieve Operations

35

API Call client.asyncGet(key, transcoder)

Description Get one or more key values

Returns Future<T> (Future value as Transcoded Object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form is identical to the first, but includes the ability to use a custom transcoder on the stored value.

6.3. Get-and-Touch Methods

The Get-and-Touch (GAT) methods obtain a value for a given key and update the expiry time for the key. This can be use-ful for session values and other information where you want to set an expiry time, but don't want the value to expire whilethe value is still in use.

API Call client.getAndTouch(key, expiry)

Description Get a value and update the expiration time for a given key

Introduced Version 1.0

Returns CASValue (Check and set object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

The first form of the getAndTouch() obtains a given value and updates the expiry time. For example, to get session da-ta and renew the expiry time to five minutes:

session = client.getAndTouch("sessionid",300);

API Call client.getAndTouch(key, expiry, transcoder)

Description Get a value and update the expiration time for a given key

Introduced Version 1.0

Returns CASValue (Check and set object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form supports the use of a custom transcoder for the stored value information.

Page 42: Couchbase Sdk Java 1.0

Retrieve Operations

36

API Call client.asyncGetAndTouch(key, expiry)

Description Get a value and update the expiration time for a given key

Introduced Version 1.0

Returns Future<CASValue<Object>> (Future value as CASValue as Object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

The asynchronous methods obtain the value and update the expiry time without requiring you to actively wait for the re-sponse. The returned value is a CAS object with the embedded value object.

Future<CASValue<Object>> future = client.asyncGetAndTouch("sessionid", 300);

CASValue casv;

try { casv = future.get(5, TimeUnit.SECONDS);} catch(Exception e) { future.cancel(false);}

API Call client.asyncGetAndTouch(key, expiry, transcoder)

Description Get a value and update the expiration time for a given key

Introduced Version 1.0

Returns Future<CASValue<T>> (Future value as CASValue as Transcoded object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the asynchronous method supports the use of a custom transcoder for the stored object.

6.4. CAS get Methods

The gets() methods obtain a CAS value for a given key. The CAS value is used in combination with the correspondingCheck-and-Set methods when updating a value. For example, you can use the CAS value with the append() operationto update a value only if the CAS value you supply matches. For more information see Section 7.1, “Append Methods”and Section 7.3, “Check-and-Set Methods”.

API Call client.gets(key)

Description Get single key value with CAS value

Returns CASValue (Check and set object)

Arguments

Page 43: Couchbase Sdk Java 1.0

Retrieve Operations

37

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

The gets() method obtains a CASValue for a given key. The CASValue holds the CAS to be used when performing aCheck-And-Set operation, and the corresponding value for the given key.

For example, to obtain the CAS and value for the key someKey:

CASValue status = client.gets("someKey");System.out.printf("CAS is %s\n",status.getCas());System.out.printf("Result was %s\n",status.getValue());

The CAS value can be used in a CAS call such as append():

client.append(status.getCas(),"someKey", "appendedstring");

API Call client.gets(key, transcoder)

Description Get single key value with CAS value

Returns CASValue (Check and set object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the gets() method supports the use of a custom transcoder.

API Call client.asyncGets(key)

Description Get single key value with CAS value

Returns Future<CASValue<Object>> (Future value as CASValue as Object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

The asyncGets() method obtains the CASValue object for a stored value against the specified key, without requiringan explicit wait for the returned value.

For example:

Future<CASValue<Object>> future = client.asyncGets("someKey");

System.out.printf("CAS is %s\n",future.get(5,TimeUnit.SECONDS).getCas());

Note that you have to extract the CASValue from the Future response, and then the CAS value from the corresponding ob-ject. This is performed here in a single statement.

API Call client.asyncGets(key, transcoder)

Description Get single key value with CAS value

Returns Future<CASValue<T>> (Future value as CASValue as Transcoded object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Page 44: Couchbase Sdk Java 1.0

Retrieve Operations

38

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The final form of the asyncGets() method supports the use of a custom transcoder.

6.5. Bulk get MethodsThe bulk getBulk() methods allow you to get one or more items from the database in a single request. Using the bulkmethods is more efficient than multiple single requests as the operation can be conducted in a single network call.

API Call client.getBulk(keycollection)

Description Get one or more key values

Returns Map<String,Object> (Map of Strings/Objects)

Arguments

Collection<String>keycollection

One or more keys used to reference a value

The first format accepts a String Collection as the request argument which is used to specify the list of keys thatyou want to retrieve. The return type is Map between the keys and object values.

For example:

Map<String,Object> keyvalues = client.getBulk(keylist);

System.out.printf("A is %s\n",keyvalues.get("keyA"));System.out.printf("B is %s\n",keyvalues.get("keyB"));System.out.printf("C is %s\n",keyvalues.get("keyC"));

Note

The returned map will only contain entries for keys that exist from the original request. For example,if you request the values for three keys, but only one exists, the resultant map will contain only thatone key/value pair.

API Call client.getBulk(keycollection, transcoder)

Description Get one or more key values

Returns Map<String,T> (Map of Strings/Transcoded objects)

Arguments

Collection<String>keycollection

One or more keys used to reference a value

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the getBulk() method supports the same Collection argument, but also supports the use of acustom transcoder on the returned values.

Note

The specified transcoder will be used for every value requested from the database.

API Call client.getBulk(keyn)

Description Get one or more key values

Returns Map<String,Object> (Map of Strings/Objects)

Page 45: Couchbase Sdk Java 1.0

Retrieve Operations

39

Arguments

String... keyn One or more keys used to reference a value

The third form of the getBulk() method supports a variable list of arguments with each interpreted as the key to be re-trieved from the database.

For example, the equivalent of the Collection method operation using this method would be:

Map<String,Object> keyvalues = client.getBulk("keyA","keyB","keyC");

System.out.printf("A is %s\n",keyvalues.get("keyA"));System.out.printf("B is %s\n",keyvalues.get("keyB"));System.out.printf("C is %s\n",keyvalues.get("keyC"));

The return Map will only contain entries for keys that exist. Non-existent keys will be silently ignored.

API Call client.getBulk(transcoder, keyn)

Description Get one or more key values

Returns Map<String,T> (Map of Strings/Transcoded objects)

Arguments

Transcoder<T>transcoder

Transcoder class to be used to serialize value

String... keyn One or more keys used to reference a value

The fourth form of the getBulk() method uses the variable list of arguments but supports a custom transcoder.

Warning

Note that unlike other formats of the methods used for supporting custom transcoders, the transcoderspecification is at the start of the argument list, not the end.

API Call client.asyncGetBulk(keycollection)

Description Get one or more key values

Returns BulkFuture<Map<String,Object>> (Map of Strings/Objects)

Arguments

Collection<String>keycollection

One or more keys used to reference a value

The asynchronous getBulk() method supports a Collection of keys to be retrieved, returning a BulkFuture ob-ject (part of the spymemcached package) with the returned map of key/value information. As with other asynchronousmethods, the benefit is that you do not need to actively wait for the response.

The BulkFuture object operates slightly different in context to the standard Future object. Whereas the Future ob-ject gets a returned single value, the BulkFuture object will return an object containing as many keys as have been re-turned. For very large queries requesting large numbers of keys this means that multiple requests may be required to ob-tain every key from the original list.

For example, the code below will obtain as many keys as possible from the supplied Collection.

BulkFuture<Map<String,Object>> keyvalues = membase.asyncGetBulk(keylist);

Map<String,Object> keymap = keyvalues.getSome(5,TimeUnit.SECONDS);

System.out.printf("A is %s\n",keymap.get("keyA"));System.out.printf("B is %s\n",keymap.get("keyB"));System.out.printf("C is %s\n",keymap.get("keyC"));

Page 46: Couchbase Sdk Java 1.0

Retrieve Operations

40

API Call client.asyncGetBulk(keycollection, transcoder)

Description Get one or more key values

Returns BulkFuture<Map<String,T>> (Map of Strings/Transcoded objects)

Arguments

Collection<String>keycollection

One or more keys used to reference a value

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the asynchronous getBulk() method supports the custom transcoder for the returned values.

API Call client.asyncGetBulk(keyn)

Description Get one or more key values

Returns BulkFuture<Map<String,Object>> (Map of Strings/Objects)

Arguments

String... keyn One or more keys used to reference a value

The third form is identical to the multi-argument key request method (see collection based asyncBulkGet()), exceptthat the operation occurs asynchronously.

API Call client.asyncGetBulk(transcoder, keyn)

Description Get one or more key values

Returns BulkFuture<Map<String,T>> (Map of Strings/Transcoded objects)

Arguments

Transcoder<T>transcoder

Transcoder class to be used to serialize value

String... keyn One or more keys used to reference a value

The final form of the asyncGetBulk() method supports a customer transcoder with the variable list of keys suppliedas arguments.

Page 47: Couchbase Sdk Java 1.0

41

Chapter 7. Update OperationsThe update methods support different methods of updating and changing existing information within Couchbase. A list ofthe available methods is listed below.

Table 7.1. Java Client Library Update Methods

Method Title

client.append(casunique, key, value) Append a value to an existing key

client.append(casunique, key, value,transcoder)

Append a value to an existing key

client.asyncCAS(key, casunique, value) Asynchronously compare and set a value

client.asyncCAS(key, casunique, expiry,value, transcoder)

Asynchronously compare and set a value with customtranscoder and expiry

client.asyncCAS(key, casunique, value,transcoder)

Asynchronously compare and set a value with customtranscoder

client.asyncDecr(key, offset) Asynchronously decrement the value of an existing key

client.asyncIncr(key, offset) Asynchronously increment the value of an existing key

client.cas(key, casunique, value) Compare and set

client.cas(key, casunique, expiry, val-ue, transcoder)

Compare and set with a custom transcoder and expiry

client.cas(key, casunique, value,transcoder)

Compare and set with a custom transcoder

client.decr(key, offset) Decrement the value of an existing numeric key

client.decr(key, offset, default) Decrement the value of an existing numeric key

client.decr(key, offset, default, ex-piry)

Decrement the value of an existing numeric key

client.delete(key) Delete the specified key

client.incr(key, offset) Increment the value of an existing numeric key

client.incr(key, offset, default) Increment the value of an existing numeric key

client.incr(key, offset, default, ex-piry)

Increment the value of an existing numeric key

client.prepend(casunique, key, value) Prepend a value to an existing key using the defaulttranscoder

client.prepend(casunique, key, value,transcoder)

Prepend a value to an existing key using a customtranscoder

client.touch(key, expiry) Update the expiry time of an item

7.1. Append MethodsThe append() methods allow you to add information to an existing key/value pair in the database. You can use this toadd information to a string or other data after the existing data.

The append() methods append raw serialized data on to the end of the existing data in the key. If you have previous-ly stored a serialized object into Couchbase and then use append, the content of the serialized object will not be extended.For example, adding an Array of integers into the database, and then using append() to add another integer will resultin the key referring to a serialized version of the array, immediately followed by a serialized version of the integer. It will

Page 48: Couchbase Sdk Java 1.0

Update Operations

42

not contain an updated array with the new integer appended to it. De-serialization of objects that have had data appendedmay result in data corruption.

API Call client.append(casunique, key, value)

Description Append a value to an existing key

Returns Object (Binary object)

Arguments

long casunique Unique value used to identify a key/value combination

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Object value Value to be stored

The append() appends information to the end of an existing key/value pair. The append() function requires a CASvalue. For more information on CAS values, see Section 6.4, “CAS get Methods”.

For example, to append a string to an existing key:

CASValue<Object> casv = client.gets("samplekey");client.append(casv.getCas(),"samplekey", "appendedstring");

You can check if the append operation succeeded by using the return OperationFuture value:

OperationFuture<Boolean> appendOp = client.append(casv.getCas(),"notsamplekey", "appendedstring");

try { if (appendOp.get().booleanValue()) { System.out.printf("Append succeeded\n"); } else { System.out.printf("Append failed\n"); }}catch (Exception e) {...}

API Call client.append(casunique, key, value, transcoder)

Description Append a value to an existing key

Returns Object (Binary object)

Arguments

long casunique Unique value used to identify a key/value combination

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the append() method supports the use of custom transcoder.

7.2. Prepend MethodsThe prepend() methods insert information before the existing data for a given key. Note that as with the append()method, the information will be inserted before the existing binary data stored in the key, which means that serialization ofcomplex objects may lead to corruption when using prepend().

Page 49: Couchbase Sdk Java 1.0

Update Operations

43

API Call client.prepend(casunique, key, value)

Description Prepend a value to an existing key

Returns Future<Boolean> (Future value as Boolean)

Arguments

long casunique Unique value used to identify a key/value combination

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Object value Value to be stored

The prepend() inserts information before the existing data stored in the key/value pair. The prepend() function re-quires a CAS value. For more information on CAS values, see Section 6.4, “CAS get Methods”.

For example, to prepend a string to an existing key:

CASValue<Object> casv = client.gets("samplekey");client.prepend(casv.getCas(),"samplekey", "prependedstring");

You can check if the prepend operation succeeded by using the return OperationFuture value:

OperationFuture<Boolean> prependOp = client.prepend(casv.getCas(),"notsamplekey", "prependedstring");

try { if (prependOp.get().booleanValue()) { System.out.printf("Prepend succeeded\n"); } else { System.out.printf("Prepend failed\n"); }}catch (Exception e) {...}

API Call client.prepend(casunique, key, value, transcoder)

Description Prepend a value to an existing key

Returns Future<Boolean> (Future value as Boolean)

Arguments

long casunique Unique value used to identify a key/value combination

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The secondary form of the prepend() method supports the use of a custom transcoder for updating the key/value pair.

7.3. Check-and-Set Methods

The check-and-set methods provide a mechanism for updating information only if the client knows the check (CAS) val-ue. This can be used to prevent clients from updating values in the database that may have changed since the client ob-tained the value. Methods for storing and updating information support a CAS method that allows you to ensure that theclient is updating the version of the data that the client retrieved.

Page 50: Couchbase Sdk Java 1.0

Update Operations

44

The check value is in the form of a 64-bit integer which is updated every time the value is modified, even if the updateof the value does not modify the binary data. Attempting to set or update a key/value pair where the CAS value does notmatch the value stored on the server will fail.

The cas() methods are used to explicitly set the value only if the CAS supplied by the client matches the CAS on theserver, analogous to the Section 5.2, “Set Operations” method.

With all CAS operations, the CASResponse value returned indicates whether the operation succeeded or not, and if notwhy. The CASResponse is an Enum with three possible values:

• EXISTS

The item exists, but the CAS value on the database does not match the value supplied to the CAS operation.

• NOT_FOUND

The specified key does not exist in the database. An add() method should be used to add the key to the database.

• OK

The CAS operation was successful and the updated value is stored in Couchbase

API Call client.cas(key, casunique, value)

Description Compare and set a value providing the supplied CAS key matches

Returns CASResponse (Check and set object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

long casunique Unique value used to identify a key/value combination

Object value Value to be stored

The first form of the cas() method allows for an item to be set in the database only if the CAS value supplied matchesthat stored on the server.

For example:

CASResponse casr = client.cas("caskey", casvalue, "new string value");

if (casr.equals(CASResponse.OK)) { System.out.println("Value was updated");}else if (casr.equals(CASResponse.NOT_FOUND)) { System.out.println("Value is not found");}else if (casr.equals(CASResponse.EXISTS)) { System.out.println("Value exists, but CAS didn't match");}

API Call client.cas(key, casunique, value, transcoder)

Description Compare and set a value providing the supplied CAS key matches

Returns CASResponse (Check and set object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

long casunique Unique value used to identify a key/value combination

Page 51: Couchbase Sdk Java 1.0

Update Operations

45

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the method supports using a custom transcoder for storing a value.

API Call client.cas(key, casunique, expiry, value, transcoder)

Description Compare and set a value providing the supplied CAS key matches

Returns CASResponse (Check and set object)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

long casunique Unique value used to identify a key/value combination

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

This form of the cas() method updates both the key value and the expiry time for the value. For information on expiryvalues, see Section 4.4, “Expiry Values”.

For example the following attempts to set the key caskey with an updated value, setting the expiry times to 3600 sec-onds (one hour).

Transcoder<Integer> tc = new IntegerTranscoder();CASResponse casr = client.cas("caskey", casvalue, 3600, 1200, tc);

API Call client.asyncCAS(key, casunique, value)

Description Compare and set a value providing the supplied CAS key matches

Returns Future<CASResponse> (Future value as CASResponse)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

long casunique Unique value used to identify a key/value combination

Object value Value to be stored

Performs an asynchronous CAS operation on the given key/value. You can use this method to set a value using CAS with-out waiting for the response. The following example requests an update of a key, timing out after 5 seconds if the opera-tion was not successful.

Future<CASResponse> future = client.asyncCAS("someKey", casvalue, "updatedvalue");

CASResponse casr;

try { casr = future.get(5, TimeUnit.SECONDS);} catch(TimeoutException e) { future.cancel(false);}

API Call client.asyncCAS(key, casunique, value, transcoder)

Page 52: Couchbase Sdk Java 1.0

Update Operations

46

Description Compare and set a value providing the supplied CAS key matches

Returns Future<CASResponse> (Future value as CASResponse)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

long casunique Unique value used to identify a key/value combination

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

Performs an asynchronous CAS operation on the given key/value using a custom transcoder. The example below showsthe update of an existing value using a custom Integer transcoder.

Transcoder<Integer> tc = new IntegerTranscoder();Future<CASResponse> future = client.asyncCAS("someKey", casvalue, 1200, tc);

CASResponse casr;

try { casr = future.get(5, TimeUnit.SECONDS);} catch(TimeoutException e) { future.cancel(false);}

API Call client.asyncCAS(key, casunique, expiry, value, transcoder)

Description Compare and set a value providing the supplied CAS key matches

Returns Future<CASResponse> (Future value as CASResponse)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

long casunique Unique value used to identify a key/value combination

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Object value Value to be stored

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The final form of the asyncCAS() method supports a custom transcoder and setting the associated expiry value. For ex-ample, to update a value and set the expiry to 60 seconds:

Transcoder<Integer> tc = new IntegerTranscoder();Future<CASResponse> future = client.asyncCAS("someKey", casvalue, 60, 1200, tc);

CASResponse casr;

try { casr = future.get(5, TimeUnit.SECONDS);} catch(TimeoutException e) { future.cancel(false);}

7.4. Delete MethodsThe delete() method deletes an item in the database with the specified key. Delete operations are asynchronous only.

Page 53: Couchbase Sdk Java 1.0

Update Operations

47

API Call client.delete(key)

Description Delete a key/value

Returns Future<Boolean> (Future value as Boolean)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

For example, to delete an item you might use code similar to the following:

OperationFuture<Boolean> delOp = client.delete("samplekey");

try { if (delOp.get().booleanValue()) { System.out.printf("Delete succeeded\n"); } else { System.out.printf("Delete failed\n"); }

}catch (Exception e) { System.out.println("Failed to delete " + e);}

7.5. Decrement Methods

The decrement methods reduce the value of a given key if the corresponding value can be parsed to an integer value.These operations are provided at a protocol level to eliminate the need to get, update, and reset a simple integer value inthe database. All the Java Client Library methods support the use of an explicit offset value that will be used to reduce thestored value in the database.

API Call client.decr(key, offset)

Description Decrement the value of an existing numeric key

Returns long (Numeric value)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

The first form of the decr() method accepts the keyname and offset value to be used when reducing the server-side inte-ger. For example, to decrement the server integer dlcounter by 5:

client.decr("dlcounter",5);

The return value is the updated value of the specified key.

API Call client.decr(key, offset, default)

Description Decrement the value of an existing numeric key

Returns long (Numeric value)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Page 54: Couchbase Sdk Java 1.0

Update Operations

48

int offset Integer offset value to increment/decrement (default 1)

int default Default value to increment/decrement if key does not exist

The second form of the decr() method will decrement the given key by the specified offset value if the key alreadyexists, or set the key to the specified default value if the key does not exist. This can be used in situations where youare recording a counter value but do not know whether the key exists at the point of storage.

For example, if the key dlcounter does not exist, the following fragment will return 1000:

long newcount = client.decr("dlcount",1,1000);

System.out.printf("Updated counter is %d\n",newcount);

A subsequent identical call will return the value 999 as the key dlcount already exists.

API Call client.decr(key, offset, default, expiry)

Description Decrement the value of an existing numeric key

Returns long (Numeric value)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

int default Default value to increment/decrement if key does not exist

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

The third form of the decr() method the decrement operation, with a default value and with the addition of setting anexpiry time on the stored value. For example, to decrement a counter, using a default of 1000 if the value does not exist,and an expiry of 1 hour (3600 seconds):

long newcount = client.decr("dlcount",1,1000,3600);

For information on expiry values, see Section 4.4, “Expiry Values”.

API Call client.asyncDecr(key, offset)

Description Decrement the value of an existing numeric key

Returns long (Numeric value)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

The asynchronous form of the asyncGet() method enables you to decrement a value without waiting for a response.This can be useful in situations where you do not need to know the updated value or merely want to perform a decrementand continue processing.

For example, to asynchronously decrement a given key:

OperationFuture<Long> decrOp = client.asyncDecr("samplekey",1,1000,24000);

Page 55: Couchbase Sdk Java 1.0

Update Operations

49

7.6. Increment Methods

The increment methods enable you to increase a given stored integer value. These are the incremental equivalent of thedecrement operations and work on the same basis; updating the value of a key if it can be parsed to an integer. The updateoperation occurs on the server and is provided at the protocol level. This simplifies what would otherwise be a two-stageget and set operation.

API Call client.incr(key, offset)

Description Increment the value of an existing numeric key

Returns long (Numeric value)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

The first form of the incr() method accepts the keyname and offset (increment) value to be used when increasing theserver-side integer. For example, to increment the server integer dlcounter by 5:

client.incr("dlcounter",5);

The return value is the updated value of the specified key.

API Call client.incr(key, offset, default)

Description Increment the value of an existing numeric key

Returns long (Numeric value)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

int default Default value to increment/decrement if key does not exist

The second form of the incr() method supports the use of a default value which will be used to set the correspondingkey if that value does already exist in the database. If the key exists, the default value is ignored and the value is incre-mented with the provided offset value. This can be used in situations where you are recording a counter value but do notknow whether the key exists at the point of storage.

For example, if the key dlcounter does not exist, the following fragment will return 1000:

long newcount = client.incr("dlcount",1,1000);

System.out.printf("Updated counter is %d\n",newcount);

A subsequent identical call will return the value 1001 as the key dlcount already exists and the value (1000) is incre-mented by 1.

API Call client.incr(key, offset, default, expiry)

Description Increment the value of an existing numeric key

Returns long (Numeric value)

Arguments

Page 56: Couchbase Sdk Java 1.0

Update Operations

50

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

int default Default value to increment/decrement if key does not exist

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

The third format of the incr() method supports setting an expiry value on the given key, in addition to a default value ifkey does not already exist.

For example, to increment a counter, using a default of 1000 if the value does not exist, and an expiry of 1 hour (3600 sec-onds):

long newcount = client.incr("dlcount",1,1000,3600);

For information on expiry values, see Section 4.4, “Expiry Values”.

API Call client.asyncIncr(key, offset)

Description Increment the value of an existing numeric key

Returns Future<Long> (Future value as Long)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int offset Integer offset value to increment/decrement (default 1)

The asyncIncr() method supports an asynchronous increment on the value for a corresponding key. Asynchronous in-crements are useful when you do not want to immediately wait for the return value of the increment operation.

OperationFuture<Long> incrOp = client.asyncIncr("samplekey",1,1000,24000);

7.7. Replace MethodsThe replace() methods update an existing key/value pair in the database. If the specified key does not exist, then theoperation will fail.

API Call client.replace(key, value, expiry)

Description Update an existing key with a new value

Returns Future<Boolean> (Future value as Boolean)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Object value Value to be stored

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

The first form of the replace() method updates an existing value setting while supporting the explicit setting of the ex-piry time on the item. For example to update the samplekey:

Page 57: Couchbase Sdk Java 1.0

Update Operations

51

OperationFuture<Boolean> replaceOp = client.replace("samplekey","updatedvalue",0);

The return value is a OperationFuture value with a Boolean base.

API Call client.replace(key, value, expiry, transcoder)

Description Update an existing key with a new value

Returns Future<Boolean> (Future value as Boolean)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

Object value Value to be stored

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

Transcoder<T>transcoder

Transcoder class to be used to serialize value

The second form of the replace() method is identical o the first, but also supports using a custom Transcoder in placeof the default transcoder.

7.8. Touch Methods

The touch() methods allow you to update the expiration time on a given key. This can be useful for situations whereyou want to prevent an item from expiring without resetting the associated value. For example, for a session database youmight want to keep the session alive in the database each time the user accesses a web page without explicitly updating thesession value, keeping the user's session active and available.

API Call client.touch(key, expiry)

Description Update the expiry time of an item

Returns Future<Boolean> (Future value as Boolean)

Arguments

String key Key used to reference the value. The key cannot containcontrol characters or whitespace.

int expiry Expiry time for key. Values larger than 30*24*60*60 sec-onds (30 days) are interpreted as absolute times (from theepoch).

The first form of the touch() provides a simple key/expiry call to update the expiry time on a given key. For example,to update the expiry time on a session for another 5 minutes:

OperationFuture<Boolean> touchOp = client.touch("sessionid",300);

Page 58: Couchbase Sdk Java 1.0

52

Chapter 8. Statistics OperationsThe Couchbase Java Client Library includes support for obtaining statistic information from all of the servers definedwithin a CouchbaseClient> object. A summary of the commands is provided below.

Table 8.1. Java Client Library Statistics Methods

Method Title

client.getStats() Get the statistics from all connections

client.getStats(statname) Get the statistics from all connections

API Call client.getStats()

Description Get the database statistics

Returns Object (Binary object)

Arguments

None

The first form of the getStats() command gets the statistics from all of the servers configured in your Couchbase-Client object. The information is returned in the form of a nested Map, first containing the address of configured server,and then within each server the individual statistics for that server.

API Call client.getStats(statname)

Description Get the database statistics

Returns Object (Binary object)

Arguments

String statname Group name of a statistic for selecting individual statisticvalue

The second form of the getStats() command gets the specified group of statistics from all of the servers configuredin your MemcachedClient object. The information is returned in the form of a nested Map, first containing the address ofconfigured server, and then within each server the individual statistics for that server.

Page 59: Couchbase Sdk Java 1.0

53

Appendix A. Release NotesThe following sections provide release notes for individual release versions of Couchbase Client Library Java. To browseor submit new issues, see Couchbase Client Library Java Issues Tracker.

A.1. Release Notes for 1.0.2 Couchbase Client Library Java GA (5 April2012)

Fixes in 1.0.2

• An issue which affects memcached bucket types, where it was found that the hashing was not compatible with Couch-base Server's proxy port (a.k.a. moxi) has been fixed in this release. It is also incompatible with the spymemcached2.7.x compatibility with Couchbase (and Membase). Note that this means the use of the 1.0.2 client is INCOM-PATIBLE with 1.0.1 and 1.0.0. JCBC-29.

• An issue which would prevent failover in some situations was fixed in this release. Prior to this fix, a permanent fail-ure of the node the client was receiving configurations from (typically from the first node in the list) would cause theclient to stick with an old configuration, and thus it would not know about any failovers or changes to cluster topology.JCBC-19.

A.2. Release Notes for 1.0.1 Couchbase Client Library Java GA (25January 2012)

Fixes in 1.0.1

• Some Maven issues with the client libraries were fixed.

• A major bug in 1.0.0 causing incorrect hashing of vBuckets was fixed and addressed in 1.0.1

A.3. Release Notes for 1.0.0 Couchbase Client Library Java GA (23January 2012)

New Features and Feature Changes in 1.0.0

• The spymemcached library functionality is now avaliable via Couchbase-client and spymemcached li-braries. Couchbase Connections, Connection Factory and the storage and retrieval operations is abstracted in the Couch-base-client library and ought to be the predominant library to be used by Java programs. Memcached functionality isstill available with spymemcached.

Consequently, the package structure has a new com.couchbase.client package in addition to the exisitingnet.spy.memcached package.

For example, the connection to Couchbase can be obtained using the Couchbase-client library objects and methods.

List<URI> uris = new LinkedList<URI>();

// Connect to localhost or to the appropriate URI uris.add(URI.create("http://127.0.0.1:8091/pools")); try { client = new CouchbaseClient(uris, "default", ""); } catch (Exception e) { System.err.println("Error connecting to Couchbase: " + e.getMessage()); System.exit(0); }

Page 60: Couchbase Sdk Java 1.0

Release Notes

54

or using the CouchbaseConnectionFactory as below.

CouchbaseConnectionFactory cf = new CouchbaseConnectionFactory(uris, "rags", "password"); client = new CouchbaseClient((CouchbaseConnectionFactory) cf);

Page 61: Couchbase Sdk Java 1.0

55

Appendix B. LicensesThis documentation and associated software is subject to the following licenses.

B.1. Documentation License

This documentation in any form, software or printed matter, contains proprietary information that is the exclusive prop-erty of Couchbase. Your access to and use of this material is subject to the terms and conditions of your Couchbase Soft-ware License and Service Agreement, which has been executed and with which you agree to comply. This document andinformation contained herein may not be disclosed, copied, reproduced, or distributed to anyone outside Couchbase with-out prior written consent of Couchbase or as specifically provided below. This document is not part of your license agree-ment nor can it be incorporated into any contractual agreement with Couchbase or its subsidiaries or affiliates.

Use of this documentation is subject to the following terms:

You may create a printed copy of this documentation solely for your own personal use. Conversion to other formats is al-lowed as long as the actual content is not altered or edited in any way. You shall not publish or distribute this documenta-tion in any form or on any media, except if you distribute the documentation in a manner similar to how Couchbase dis-seminates it (that is, electronically for download on a Web site with the software) or on a CD-ROM or similar medium,provided however that the documentation is disseminated together with the software on the same medium. Any other use,such as any dissemination of printed copies or use of this documentation, in whole or in part, in another publication, re-quires the prior written consent from an authorized representative of Couchbase. Couchbase and/or its affiliates reserveany and all rights to this documentation not expressly granted above.

This documentation may provide access to or information on content, products, and services from third parties. CouchbaseInc. and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-partycontent, products, and services. Couchbase Inc. and its affiliates will not be responsible for any loss, costs, or damages in-curred due to your access to or use of third-party content, products, or services.

The information contained herein is subject to change without notice and is not warranted to be error-free. If you find anyerrors, please report them to us in writing.