Java tutorial
/** * Copyright (C) 2009-2013 Couchbase, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING * IN THE SOFTWARE. */ package com.couchbase.client; import com.couchbase.client.clustermanager.AuthType; import com.couchbase.client.clustermanager.BucketType; import com.couchbase.client.clustermanager.FlushResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.net.URI; import java.util.LinkedList; import java.util.List; import net.spy.memcached.compat.SpyObject; import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.entity.StringEntity; import org.apache.http.impl.DefaultHttpClientConnection; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.params.SyncBasicHttpParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpProcessor; import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.protocol.ImmutableHttpProcessor; import org.apache.http.protocol.RequestConnControl; import org.apache.http.protocol.RequestContent; import org.apache.http.protocol.RequestExpectContinue; import org.apache.http.protocol.RequestTargetHost; import org.apache.http.protocol.RequestUserAgent; import org.apache.http.util.EntityUtils; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; /** * A client for the Couchbase REST API. */ public class ClusterManager extends SpyObject { private DefaultHttpClientConnection conn; private HttpContext context; private HttpHost host; private HttpRequestExecutor httpexecutor; private HttpProcessor httpproc; private final List<URI> addrs; private final String user; private final String pass; /** * Creates a connection to the Couchbase REST interface. * * @param uris A list of servers in the cluster. * @param username The cluster admin user name. * @param password The cluster admin password. */ public ClusterManager(List<URI> uris, String username, String password) { addrs = uris; user = username; pass = password; httpproc = new ImmutableHttpProcessor( new HttpRequestInterceptor[] { new RequestContent(), new RequestTargetHost(), new RequestConnControl(), new RequestUserAgent(), new RequestExpectContinue() }); httpexecutor = new HttpRequestExecutor(); context = new BasicHttpContext(null); conn = new DefaultHttpClientConnection(); } /** * Connects to a given server if a connection has not been made to at least * one of the servers in the server list already. * @param uri * @return */ private boolean connect(URI uri) { host = new HttpHost(uri.getHost(), uri.getPort()); context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host); try { if (!conn.isOpen()) { Socket socket = new Socket(host.getHostName(), host.getPort()); conn.bind(socket, new SyncBasicHttpParams()); } return true; } catch (IOException e) { return false; } } /** * Creates the default bucket. * * @param type The bucket type to create. * @param memorySizeMB The amount of memory to allocate to this bucket. * @param replicas The number of replicas for this bucket. * @param flushEnabled If flush should be enabled on this bucket. */ public void createDefaultBucket(BucketType type, int memorySizeMB, int replicas, boolean flushEnabled) { createBucket(type, "default", memorySizeMB, AuthType.NONE, replicas, 11212, "", flushEnabled); } /** * Creates a named bucket with a given password for SASL authentication. * * @param type The bucket type to create. * @param name The name of the bucket. * @param memorySizeMB The amount of memory to allocate to this bucket. * @param replicas The number of replicas for this bucket. * @param authPassword The password for this bucket. * @param flushEnabled If flush should be enabled on this bucket. */ public void createNamedBucket(BucketType type, String name, int memorySizeMB, int replicas, String authPassword, boolean flushEnabled) { createBucket(type, name, memorySizeMB, AuthType.SASL, replicas, 11212, authPassword, flushEnabled); } /** * Creates the a sasl bucket. * * @param type The bucket type to create. * @param name The name of the bucket. * @param memorySizeMB The amount of memory to allocate to this bucket. * @param replicas The number of replicas for this bucket. * @param port The port for this bucket to listen on. */ public void createPortBucket(BucketType type, String name, int memorySizeMB, int replicas, int port, boolean flush) { createBucket(type, name, memorySizeMB, AuthType.NONE, replicas, port, "", flush); } /** * Deletes a bucket. * * @param name The name of the bucket to delete. */ public void deleteBucket(String name) { String url = "/pools/default/buckets/" + name; BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("DELETE", url); checkError(200, sendRequest(request)); } /** * Lists all buckets in a Couchbase cluster. */ public List<String> listBuckets() { String url = "/pools/default/buckets/"; BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("GET", url); HttpResult result = sendRequest(request); checkError(200, result); String json = result.getBody(); List<String> names = new LinkedList<String>(); if (json != null && !json.equals("")) { try { JSONArray base = new JSONArray(json); for (int i = 0; i < base.length(); i++) { JSONObject bucket = (JSONObject) base.get(i); if (bucket.has("name")) { names.add(bucket.getString("name")); } } } catch (JSONException e) { getLogger().error("Unable to interpret list buckets response."); throw new RuntimeException(e); } } return names; } /** * Deletes all data in a bucket. * * @param name The bucket to flush. */ public FlushResponse flushBucket(String name) { String url = "/pools/default/buckets/" + name + "/controller/doFlush"; BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", url); HttpResult result = sendRequest(request); if (result.getErrorCode() == 200) { return FlushResponse.OK; } else if (result.getErrorCode() == 400) { return FlushResponse.NOT_ENABLED; } else { throw new RuntimeException("Http Error: " + result.getErrorCode() + " Reason: " + result.getErrorPhrase() + " Details: " + result.getReason()); } } private void createBucket(BucketType type, String name, int memorySizeMB, AuthType authType, int replicas, int port, String authpassword, boolean flushEnabled) { BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/pools/default/buckets"); StringBuilder sb = new StringBuilder(); sb.append("name=").append(name); sb.append("&ramQuotaMB=").append(memorySizeMB); sb.append("&authType=").append(authType.getAuthType()); sb.append("&replicaNumber=").append(replicas); sb.append("&bucketType=").append(type.getBucketType()); sb.append("&proxyPort=").append(port); if (authType == AuthType.SASL) { sb.append("&saslPassword=").append(authpassword); } if (flushEnabled) { sb.append("&flushEnabled=1"); } try { request.setEntity(new StringEntity(sb.toString())); } catch (UnsupportedEncodingException e) { getLogger().error("Error creating request. Bad arguments"); throw new RuntimeException(e); } checkError(202, sendRequest(request)); } private HttpResult sendRequest(HttpRequest request) { HttpParams params = new SyncBasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setUserAgent(params, "Couchbase Java Client/1.1"); HttpProtocolParams.setUseExpectContinue(params, true); request.addHeader("Authorization", "Basic " + Base64.encodeBase64String((user + ":" + pass).getBytes())); request.addHeader("Accept", "*/*"); request.addHeader("Content-Type", "application/x-www-form-urlencoded"); for (int i = 0; i < addrs.size(); i++) { try { if (!connect(addrs.get(i))) { continue; } httpexecutor.preProcess(request, httpproc, context); HttpResponse response = httpexecutor.execute(request, conn, context); httpexecutor.postProcess(response, httpproc, context); int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); String reason = parseError(body); String phrase = response.getStatusLine().getReasonPhrase(); return new HttpResult(body, code, phrase, reason); } catch (HttpException e) { getLogger().debug("Error processing http request: " + e.getMessage()); throw new RuntimeException(e); } catch (IOException e) { getLogger().debug("Unable to connect to: " + addrs.get(i) + ". Trying another server"); } } throw new RuntimeException("Unable to connect to cluster"); } private String parseError(String json) { if (json != null && !json.equals("")) { try { JSONObject base = new JSONObject(json); if (base.has("errors")) { JSONObject errors = (JSONObject) base.get("errors"); return errors.toString(); } } catch (JSONException e) { return "Client error parsing error response"; } } return "No reason given"; } private void checkError(int expectedCode, HttpResult result) { if (result.getErrorCode() != expectedCode) { throw new RuntimeException("Http Error: " + result.getErrorCode() + " Reason: " + result.getErrorPhrase() + " Details: " + result.getReason()); } } public boolean shutdown() { try { conn.close(); return true; } catch (IOException e) { return false; } } private final class HttpResult { private final String body; private final int errorCode; private final String errorPhrase; private final String errorReason; public HttpResult(String entity, int code, String phrase, String reason) { body = entity; errorCode = code; errorPhrase = phrase; errorReason = reason; } public String getBody() { return body; } public int getErrorCode() { return errorCode; } public String getErrorPhrase() { return errorPhrase; } public String getReason() { return errorReason; } } }