All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.myjeeva.digitalocean.impl.DigitalOceanClient Maven / Gradle / Ivy

There is a newer version: 2.17
Show newest version
/* The MIT License
 *
 * Copyright (c) 2010-2013 Jeevanandam M. (myjeeva.com)
 *
 * 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 DEALINGS IN
 * THE SOFTWARE. 
 * 
 */
package com.myjeeva.digitalocean.impl;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.myjeeva.digitalocean.Constants;
import com.myjeeva.digitalocean.DigitalOcean;
import com.myjeeva.digitalocean.Utils;
import com.myjeeva.digitalocean.common.Action;
import com.myjeeva.digitalocean.exception.AccessDeniedException;
import com.myjeeva.digitalocean.exception.RequestUnsuccessfulException;
import com.myjeeva.digitalocean.exception.ResourceNotFoundException;
import com.myjeeva.digitalocean.pojo.Domain;
import com.myjeeva.digitalocean.pojo.DomainRecord;
import com.myjeeva.digitalocean.pojo.Droplet;
import com.myjeeva.digitalocean.pojo.DropletImage;
import com.myjeeva.digitalocean.pojo.DropletSize;
import com.myjeeva.digitalocean.pojo.Region;
import com.myjeeva.digitalocean.pojo.Response;
import com.myjeeva.digitalocean.pojo.SshKey;

/**
 * DigitalOcean API client wrapper methods Implementation
 * 
 * @author Jeevanandam M. ([email protected])
 */
@SuppressWarnings("unchecked")
public class DigitalOceanClient implements DigitalOcean, Constants {

	private final Logger LOG = LoggerFactory
			.getLogger(DigitalOceanClient.class);

	/**
	 * Http client
	 */
	private HttpClient httpClient;

	/**
	 * User's Client ID
	 */
	private String clientId;

	/**
	 * User's API key
	 */
	private String apiKey;

	/**
	 * DigitalOcean API Host is api.digitalocean.com
	 */
	private String apiHost = "api.digitalocean.com";

	/**
	 * Constructor for initializing DigitalOcean Client
	 * 
	 * @param clientId
	 *            a {@link String} object
	 * @param apiKey
	 *            a {@link String} object
	 * @throws ResourceNotFoundException
	 */
	public DigitalOceanClient(String clientId, String apiKey) {
		this.clientId = clientId;
		this.apiKey = apiKey;

		// Initializing required variable(s)
		this.httpClient = new DefaultHttpClient(
				new PoolingClientConnectionManager());

	}

	@Override
	public List getAvailableDroplets() throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (List) processByScope(Action.AVAILABLE_DROPLETS,
				TYPE_DROPLET_LIST);
	}

	@Override
	public Droplet createDroplet(Droplet droplet) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return createDroplet(droplet, null);
	}

	@Override
	public Droplet createDroplet(Droplet droplet, String sshKeyIds)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {

		Map qp = new HashMap();
		qp.put(PARAM_NAME, droplet.getName());
		qp.put(PARAM_SIDE_ID, String.valueOf(droplet.getSizeId()));
		qp.put(PARAM_IMAGE_ID, String.valueOf(droplet.getImageId()));
		qp.put(PARAM_REGION_ID, String.valueOf(droplet.getRegionId()));

		if (null != sshKeyIds) {
			qp.put(PARAM_SSH_KEY_IDS, sshKeyIds);
		}

		return (Droplet) processByScope(Action.CREATE_DROPLET, Droplet.class,
				qp);
	}

	@Override
	public Droplet getDropletInfo(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return (Droplet) processByScope(Action.GET_DROPLET_INFO, Droplet.class,
				dropletId);
	}

	@Override
	public Response rebootDroplet(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.REBOOT_DROPLET, dropletId);
	}

	@Override
	public Response powerCyleDroplet(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.POWER_CYCLE_DROPLET, dropletId);
	}

	@Override
	public Response shutdownDroplet(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.SHUTDOWN_DROPLET, dropletId);
	}

	@Override
	public Response powerOffDroplet(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.POWER_OFF_DROPLET, dropletId);
	}

	@Override
	public Response powerOnDroplet(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.POWER_ON_DROPLET, dropletId);
	}

	@Override
	public Response resetDropletPassword(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.RESET_PASSWORD_DROPLET, dropletId);
	}

	@Override
	public Response resizeDroplet(Integer dropletId, Integer sizeId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_SIDE_ID, String.valueOf(sizeId));
		Object[] params = {dropletId};

		return process(Action.RESIZE_DROPLET, params, qp);
	}

	@Override
	public Response takeDropletSnapshot(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return takeDropletSnapshot(dropletId, null);
	}

	@Override
	public Response takeDropletSnapshot(Integer dropletId, String snapshotName)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Response response = null;
		if (null == snapshotName) {
			response = process(Action.TAKE_DROPLET_SNAPSHOT, dropletId);
		} else {
			Map qp = new HashMap();
			qp.put(PARAM_NAME, snapshotName);
			response = process(Action.TAKE_DROPLET_SNAPSHOT, dropletId, qp);
		}

		return response;
	}

	@Override
	public Response restoreDroplet(Integer dropletId, Integer imageId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_IMAGE_ID, String.valueOf(imageId));
		Object[] params = {dropletId};

		return process(Action.RESTORE_DROPLET, params, qp);
	}

	@Override
	public Response rebuildDroplet(Integer dropletId, Integer imageId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_IMAGE_ID, String.valueOf(imageId));
		Object[] params = {dropletId};

		return process(Action.REBUILD_DROPLET, params, qp);
	}

	@Override
	public Response enableDropletBackups(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.ENABLE_AUTOMATIC_BACKUPS, dropletId);
	}

	@Override
	public Response disableDropletBackups(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.DISABLE_AUTOMATIC_BACKUPS, dropletId);
	}

	@Override
	public Response renameDroplet(Integer dropletId, String name)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_NAME, String.valueOf(name));
		Object[] params = {dropletId};

		return process(Action.RENAME_DROPLET, params, qp);
	}

	@Override
	public Response deleteDroplet(Integer dropletId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.DELETE_DROPLET, dropletId);
	}

	@Override
	public List getAvailableRegions() throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (List) processByScope(Action.AVAILABLE_REGIONS,
				TYPE_REGION_LIST);
	}

	@Override
	public List getAvailableImages()
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return (List) processByScope(Action.AVAILABLE_IMAGES,
				TYPE_IMAGE_LIST);
	}

	@Override
	public DropletImage getImageInfo(Integer imageId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return (DropletImage) processByScope(Action.GET_IMAGE_INFO,
				DropletImage.class, imageId);
	}

	@Override
	public Response deleteImage(Integer imageId) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return process(Action.DELETE_IMAGE, imageId);
	}

	@Override
	public Response transferImage(Integer imageId, Integer regionId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_REGION_ID, String.valueOf(regionId));
		Object[] params = {imageId};

		return process(Action.TRANSFER_IMAGE, params, qp);
	}

	@Override
	public List getAvailableSshKeys() throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (List) processByScope(Action.AVAILABLE_SSH_KEYS,
				TYPE_SSH_KEY_LIST);
	}

	@Override
	public SshKey getSshKeyInfo(Integer sshKeyId) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (SshKey) processByScope(Action.GET_SSH_KEY, SshKey.class,
				sshKeyId);
	}

	@Override
	public SshKey addSshKey(String sshKeyName, String sshPublicKey)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_NAME, sshKeyName);
		qp.put(PARAM_SSH_PUB_KEY, sshPublicKey);

		return (SshKey) processByScope(Action.CREATE_SSH_KEY, SshKey.class, qp);
	}

	@Override
	public SshKey editSshKey(Integer sshKeyId, String newSshPublicKey)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_SSH_PUB_KEY, newSshPublicKey);

		return (SshKey) processByScope(Action.EDIT_SSH_KEY, SshKey.class, qp,
				sshKeyId);
	}

	@Override
	public Response deleteSshKey(Integer sshKeyId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.DELETE_SSH_KEY, sshKeyId);
	}

	@Override
	public List getAvailableSizes() throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (List) processByScope(Action.AVAILABLE_SIZES,
				TYPE_SIZE_LIST);
	}

	@Override
	public List getAvailableDomains() throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (List) processByScope(Action.AVAILABLE_DOMAINS,
				TYPE_DOMAIN_LIST);
	}

	@Override
	public Domain getDomainInfo(Integer domainId) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (Domain) processByScope(Action.GET_DOMAIN_INFO, Domain.class,
				domainId);
	}

	@Override
	public Domain createDomain(String domainName, String ipAddress)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Map qp = new HashMap();
		qp.put(PARAM_NAME, domainName);
		qp.put(PARAM_IP_ADDRESS, ipAddress);

		return (Domain) processByScope(Action.CREATE_DOMAIN, Domain.class, qp);
	}

	@Override
	public Response deleteDomain(Integer domainId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.DELETE_DOMAIN, domainId);
	}

	@Override
	public List getDomainRecords(Integer domainId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return (List) processByScope(Action.GET_DOMAIN_RECORDS,
				TYPE_DOMAIN_RECORD_LIST, domainId);
	}

	@Override
	public DomainRecord getDomainRecordInfo(Integer domainId, Integer recordId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Object[] params = {domainId, recordId};
		return (DomainRecord) processByScope(Action.GET_DOMAIN_RECORD_INFO,
				DomainRecord.class, params);
	}

	@Override
	public DomainRecord createDomainRecord(DomainRecord domainRecord)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return (DomainRecord) processByScope(Action.CREATE_DOMAIN_RECORD,
				DomainRecord.class,
				Utils.prepareDomainRecordParams(domainRecord),
				domainRecord.getDomainId());
	}

	@Override
	public DomainRecord editDomainRecord(DomainRecord domainRecord)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Object[] params = {domainRecord.getDomainId(), domainRecord.getId()};
		return (DomainRecord) processByScope(Action.EDIT_DOMAIN_RECORD,
				DomainRecord.class,
				Utils.prepareDomainRecordParams(domainRecord), params);
	}

	@Override
	public Response deleteDomainRecord(Integer domainId, Integer recordId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		Object[] params = {domainId, recordId};
		return process(Action.DELETE_DOMAIN_RECORD, params);
	}

	@Override
	public Response getEventProgress(Integer eventId)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(Action.GET_EVENT_PROGRESS, eventId);
	}

	private JsonObject performAction(Action action,
			Map queryParams, Object... pathParams)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		URI uri = generateUri(action.getMapPath(), queryParams, pathParams);

		String response = "";
		try {
			response = execute(uri);
		} catch (ClientProtocolException cpe) {
			throw new RequestUnsuccessfulException(cpe.getMessage(), cpe);
		} catch (IOException ioe) {
			throw new RequestUnsuccessfulException(ioe.getMessage(), ioe);
		}

		JsonElement element = new JsonParser().parse(response);
		JsonObject obj = element.getAsJsonObject();
		String status = obj.get(STATUS).getAsString();
		LOG.info("DigitalOcean Response Status: " + status);

		if ("OK".equalsIgnoreCase(status)) {
			LOG.debug("JSON Respose Data: " + obj.toString());
			return obj;
		} else {
			throw new RequestUnsuccessfulException(
					"DigitalOcean API request unsuccessful, possible reason colud be incorrect values ["
							+ uri + "].");
		}
	}

	private URI generateUri(String path, Map queryParams,
			Object... pathParams) {

		URIBuilder ub = new URIBuilder();
		ub.setScheme(HTTPS_SCHEME);
		ub.setHost(apiHost);
		ub.setPath(String.format(path, pathParams));
		ub.setParameter(PARAM_CLIENT_ID, this.clientId);
		ub.setParameter(PARAM_API_KEY, this.apiKey);

		if (null != queryParams) {
			for (Map.Entry entry : queryParams.entrySet()) {
				ub.setParameter(entry.getKey(), entry.getValue());
			}
		}

		URI uri = null;
		try {
			uri = ub.build();
		} catch (URISyntaxException use) {
			LOG.error(use.getMessage(), use);
		}

		return uri;
	}

	private String execute(URI uri) throws ClientProtocolException,
			IOException, AccessDeniedException, ResourceNotFoundException {
		HttpGet httpGet = new HttpGet(uri);
		LOG.debug("DigitalOcean API Endpoint URI: " + uri);

		String response = "";
		try {
			HttpResponse httpResponse = httpClient.execute(httpGet);

			if (401 == httpResponse.getStatusLine().getStatusCode()) {
				throw new AccessDeniedException(
						"Request failed to authenticate into the DigitalOcean API successfully");
			}

			if (404 == httpResponse.getStatusLine().getStatusCode()) {
				throw new ResourceNotFoundException(
						"Requested resource is not available DigitalOcean");
			}

			HttpEntity entity = httpResponse.getEntity();

			if (null != entity) {
				InputStream input = entity.getContent();
				response = Utils.readInputStream(input);

				// Let's close the stream
				try {
					if (null != input) {
						input.close();
					}
				} catch (IOException ioe) {
					LOG.error("Error occured while reading HTTP input stream ["
							+ ioe.getMessage() + "]");
				}

				LOG.debug("HTTP Response: " + response);
			}

		} finally {
			httpGet.releaseConnection();
		}

		return response;
	}

	private Response process(Action action, Object... id)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return process(action, id, null);
	}

	private Response process(Action action, Object[] id,
			Map queryParams) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return (Response) Utils.byClass(performAction(action, queryParams, id),
				Response.class);
	}

	private Object processByScope(Action action, Class clazz,
			Object... pathParams) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return processByScope(action, clazz, null, pathParams);
	}

	private Object processByScope(Action action, Class clazz,
			Map queryParams, Object... pathParams)
			throws AccessDeniedException, ResourceNotFoundException,
			RequestUnsuccessfulException {
		return Utils.byClass(performAction(action, queryParams, pathParams)
				.get(action.getElementName()), clazz);
	}

	private Object processByScope(Action action, Type type,
			Object... pathParams) throws AccessDeniedException,
			ResourceNotFoundException, RequestUnsuccessfulException {
		return Utils.byType(
				performAction(action, null, pathParams).get(
						action.getElementName()), type);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy