Package com.couchbase.client

Source Code of com.couchbase.client.ClusterManager$HttpResult

/**
* 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 final DefaultHttpClientConnection conn;
  private final HttpContext context;
  private final HttpRequestExecutor httpexecutor;
  private final 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) {
    HttpHost 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) {

      List<String> buckets = listBuckets();
      if(buckets.contains(name)){
        throw new RuntimeException("Bucket with given name already exists");
      } else {
      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()));
        System.out.println(request.toString());
      } catch (UnsupportedEncodingException e) {
        getLogger().error("Error creating request. Bad arguments");
        throw new RuntimeException(e);
      }

      checkError(202, sendRequest(request));
    }
  }

  public void updateBucket(String name, int memorySizeMB,
    AuthType authType, int replicas, int port,
    String authpassword, boolean flushEnabled) {

    try {
      BasicHttpEntityEnclosingRequest request =
      new BasicHttpEntityEnclosingRequest("POST", "/pools/default/buckets/"+name);

      StringBuilder sb = new StringBuilder();
      sb.append("&ramQuotaMB=").append(memorySizeMB);
      sb.append("&authType=").append(authType.getAuthType());
      sb.append("&replicaNumber=").append(replicas);
      sb.append("&proxyPort=").append(port);
      if (authType == AuthType.SASL) {
        sb.append("&saslPassword=").append(authpassword);
      }
      if(flushEnabled) {
        sb.append("&flushEnabled=1");
      }

      request.setEntity(new StringEntity(sb.toString()));
      checkError(200, sendRequest(request));
    } catch (UnsupportedEncodingException e) {
      getLogger().error("Error creating request. Bad arguments");
      throw new RuntimeException(e);
    }
  }


  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;
    }
  }
}
TOP

Related Classes of com.couchbase.client.ClusterManager$HttpResult

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.