public interface DigitalOcean {

  // ===========================================
  // Droplets methods
  // ===========================================

  /**
   * Method returns all active droplets that are currently running in your account. All available
   * API information is presented for each droplet.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Droplets}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Droplets getAvailableDroplets(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all available kernels for given droplet ID
   *
   * @param dropletId for kernel info
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Kernels}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Kernels getDropletKernels(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all available snapshots for given droplet ID
   *
   * @param dropletId for snapshot info
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Snapshots}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Snapshots getDropletSnapshots(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all available snapshots for given droplet ID
   *
   * @param dropletId for backup info
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Backups}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Backups getDropletBackups(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns complete information for given droplet ID
   *
   * @param dropletId the id of the droplet
   * @return {@link Droplet}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Droplet getDropletInfo(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to create a new droplet. See the required parameters section below for an
   * explanation of the variables that are needed to create a new droplet.
   *
   * <p><strong>Note:</strong> Currently return object doesn't include 'action' information of
   * create droplet.
   *
   * <p>Create a instance of {@link Droplet} class and populated the droplet object appropriately.
   * Minimum required values are -
   *
   * <pre>
   * {
   *   "name": "example-droplet-name",
   *   "region": "nyc1",
   *   "size": "512mb",
   *   "image": "ubuntu-14-04-x64",
   *   "backups": false
   * }
   * </pre>
   *
   * @param droplet the instance of the droplet class
   * @return {@link Droplet}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Droplet createDroplet(Droplet droplet) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to create multiple droplets simultaneously. See the required parameters
   * section below for an explanation of the variables that are needed to create multiple droplets.
   *
   * <p>Create a instance of {@link Droplet} class and populated the droplet object appropriately.
   * Particularly <strong>names</strong> attribute in the Droplet class. Minimum required values are
   * -
   *
   * <pre>
   * {
   *   "names": [
   *       "sub-01.example.com",
   *       "sub-02.example.com"
   *   ],
   *   "region": "nyc1",
   *   "size": "512mb",
   *   "image": "ubuntu-14-04-x64",
   *   "backups": false
   * }
   * </pre>
   *
   * @param droplet the instance of the droplet class
   * @return {@link Droplet}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Droplets createDroplets(Droplet droplet)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method destroys one of your droplet; this is irreversible.
   *
   * @param dropletId the id of the droplet
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Delete deleteDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method destroys one or more of your droplet by given tag name; this is irreversible.
   *
   * @param tagName the associated tag name with droplet
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.9
   */
  Delete deleteDropletByTagName(String tagName)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * For an individual droplet; Method retrieves a list of droplets that are running on the same
   * physical server (any other droplets that share the same physical hardware).
   *
   * @param dropletId the id of the droplet
   * @param pageNo for pagination
   * @return {@link Droplets}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Droplets getDropletNeighbors(Integer dropletId, Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * For an entire account; Method retrieves a list of <strong>any</strong> droplets that are
   * running on the same physical server (any other droplets that share the same physical hardware).
   *
   * @param pageNo for pagination
   * @return {@link Neighbors}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Neighbors getAllDropletNeighbors(Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * To list Droplets by a tag.
   *
   * <p>The response will match that of regular droplet listing request but will be filtered to only
   * include the tagged Droplets.
   *
   * @param tagName for tagName
   * @param pageNo for pagination
   * @param perPage for pagination
   * @return {@link Droplets}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.16
   */
  Droplets getAvailableDropletsByTagName(String tagName, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Droplet Action methods
  // ===========================================

  /**
   * Method allows you to reboot a droplet. This is the preferred method to use if a server is not
   * responding.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action rebootDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to power cycle a droplet. This will turn off the droplet and then turn it
   * back on.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action powerCycleDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to shutdown a running droplet.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action shutdownDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to poweroff a running droplet.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action powerOffDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to poweron a powered off droplet.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action powerOnDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will reset the root password for a droplet. Please be aware that this will reboot the
   * droplet to allow resetting the password.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action resetDropletPassword(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to resize a specific droplet to a different size. This will affect the number
   * of processors and memory allocated to the droplet.
   *
   * @param dropletId the id of the droplet
   * @param size of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action resizeDroplet(Integer dropletId, String size)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to resize a specific droplet to a different size. This will affect the number
   * of processors and memory allocated to the droplet and optionally disk size.
   *
   * @param dropletId the id of the droplet
   * @param size of the droplet
   * @param disk whether to resize disk of the droplet or or not
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action resizeDroplet(Integer dropletId, String size, Boolean disk)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to take a snapshot of the running droplet, which can later be restored or
   * used to create a new droplet from the same image. Please be aware this may cause a reboot.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action takeDropletSnapshot(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to take a snapshot of the running droplet, which can later be restored or
   * used to create a new droplet from the same image. Please be aware this may cause a reboot.
   *
   * @param dropletId the id of the droplet
   * @param snapshotName the name the snapshot to be created
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action takeDropletSnapshot(Integer dropletId, String snapshotName)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to restore a droplet with a previous image or snapshot. This will be a mirror
   * copy of the image or snapshot to your droplet. Be sure you have backed up any necessary
   * information prior to restore.
   *
   * @param dropletId the id of the droplet
   * @param imageId the id of the DigitalOcean public image or your private image
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action restoreDroplet(Integer dropletId, Integer imageId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to reinstall a droplet with a default image. This is useful if you want to
   * start again but retain the same IP address for your droplet.
   *
   * @param dropletId the id of the droplet
   * @param imageId the id of the DigitalOcean public image or your private image
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action rebuildDroplet(Integer dropletId, Integer imageId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method enables automatic backups for your droplet's data.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Action enableDropletBackups(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method disables automatic backups from running to backup your droplet's data.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action disableDropletBackups(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method renames the droplet to the specified name.
   *
   * @param dropletId the id of the droplet
   * @param name the new name of droplet to be called
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action renameDroplet(Integer dropletId, String name)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method changes a OS kernel for given droplet
   *
   * @param dropletId the id of the droplet
   * @param kernelId the kernel id to be changed for droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Action changeDropletKernel(Integer dropletId, Integer kernelId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Enabling IP v6 networking capability for droplet. It may be dependent on Data Center Features.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   */
  Action enableDropletIpv6(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Enabling private networking capability for droplet. It may be dependent on Data Center
   * Features.
   *
   * @param dropletId the id of the droplet
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Action enableDropletPrivateNetworking(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ==============================================
  // Account manipulation/access methods
  // ==============================================

  /**
   * Method returns account information for provided credentials
   *
   * @return ${@link Account}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   */
  Account getAccountInfo() throws DigitalOceanException, RequestUnsuccessfulException;

  // ==============================================
  // Actions manipulation/access methods
  // ==============================================

  /**
   * Method return all the action informations, regardless of categories.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Actions}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Actions getAvailableActions(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * To retrieve a specific action information by action ID
   *
   * @param actionId the id of action
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Action getActionInfo(Integer actionId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method return all the action informations; specific to given Droplet Id
   *
   * @param dropletId the id of the droplet
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Actions}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Actions getAvailableDropletActions(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method return all the action informations; specific to given Image Id
   *
   * @param imageId the id of the Image
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Actions}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Actions getAvailableImageActions(Integer imageId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method retrives all actions that have been executed on a Floating IP address.
   *
   * @param ipAddress Floating IP address
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Actions}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Actions getAvailableFloatingIPActions(String ipAddress, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method to retrieve the status of a Floating IP action.
   *
   * @param ipAddress Floating IP address
   * @param actionId the id of action
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Action getFloatingIPActionInfo(String ipAddress, Integer actionId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ==============================================
  // Images manipulation (aka Distribution) methods
  // ==============================================

  /**
   * Method returns all the available images that can be accessed by your OAuth Token. You will have
   * access to all public images by default, and any snapshots or backups that you have created in
   * your own account.
   *
   * @param pageNo of request pagination
   * @param perPage no. of items per page
   * @return {@link Images}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Images getAvailableImages(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all the available images based on <code>type={distribution or application}
   * </code> that can be accessed by your OAuth Token.
   *
   * @param pageNo of request pagination
   * @param perPage no. of items per page
   * @param type of action
   * @return {@link Images}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Images getAvailableImages(Integer pageNo, Integer perPage, ActionType type)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method retrieves only the private images of a user
   *
   * @param pageNo of request pagination
   * @param perPage no. of items per page
   * @return {@link Images}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   */
  Images getUserImages(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method retrieves the attributes of an image.
   *
   * @param imageId the image Id of the droplet/snapshot/backup images
   * @return {@link Image}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Image getImageInfo(Integer imageId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method retrieves the attributes of an image.
   *
   * @param slug of the public image
   * @return {@link Image}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Image getImageInfo(String slug) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method creates the custom image.
   *
   * <p>Refer to <a
   * href="https://developers.digitalocean.com/documentation/v2/#create-a-custom-image">
   * https://developers.digitalocean.com/documentation/v2/#create-a-custom-image</a>
   *
   * <p>Sample Payload:
   *
   * <pre>
   * {
   *   "name": "ubuntu-18.04-minimal",
   *   "url": "http://cloud-images.ubuntu.com/minimal/releases/bionic/release/ubuntu-18.04-minimal-cloudimg-amd64.img",
   *   "distribution": "Ubuntu",
   *   "region": "nyc3",
   *   "description": "Cloud-optimized image w/ small footprint",
   *   "tags": [
   *     "base-image",
   *     "prod"
   *   ]
   * }
   * </pre>
   *
   * @param image instance with custom image attributes
   * @return {@link Image}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.17
   */
  Image createCustomImage(Image image) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method updates the given details for an image.
   *
   * @param image object for update
   * @return {@link Image}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Image updateImage(Image image) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to deletes an image. There is no way to restore a deleted image so be careful
   * and ensure your data is properly backed up.
   *
   * @param imageId of the droplet/snapshot/backup images
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Delete deleteImage(Integer imageId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to transfer an image to a specified region.
   *
   * @param imageId the Id of the droplet/snapshot/backup images
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Action transferImage(Integer imageId, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to convert image into snapshot
   *
   * @param imageId the Id of the droplet/snapshot/backup images
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Action convertImage(Integer imageId) throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Regions (aka Data Centers) methods
  // ===========================================

  /**
   * Method returns all the available regions within the DigitalOcean cloud.
   *
   * @param pageNo for pagination
   * @return {@link Regions}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Regions getAvailableRegions(Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Sizes (aka Available Droplet Plans) methods
  // ===========================================

  /**
   * Method returns all the available sizes that can be used to create a droplet.
   *
   * @param pageNo for pagination
   * @return {@link Sizes}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Sizes getAvailableSizes(Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Domain manipulation methods
  // ===========================================

  /**
   * Method returns all of your available domains from DNS control panel
   *
   * @param pageNo for pagination
   * @return {@link Domains}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Domains getAvailableDomains(Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns the specified domain attributes and zone file info.
   *
   * @param domainName the name of the domain
   * @return {@link Domain}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Domain getDomainInfo(String domainName)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method creates a new domain name with an A record for the specified [ip_address].
   *
   * @param domain object with name and IP address for creation
   * @return {@link Domain}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Domain createDomain(Domain domain) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes the specified domain from DNS control panel
   *
   * @param domainName the name of the domain
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.0
   */
  Delete deleteDomain(String domainName) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all of your current domain records from DNS control panel for given domain.
   *
   * @param domainName of the domain
   * @param pageNo of request pagination
   * @param perPage no. of items per page
   * @return {@link DomainRecords}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.1
   */
  DomainRecords getDomainRecords(String domainName, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method creates a new domain record name with an given domain record values
   *
   * @param domainName of the domain
   * @param domainRecord the domain record values domain Id, record type, data, name, priority,
   *     port, weight
   * @return {@link DomainRecord}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.1
   */
  DomainRecord createDomainRecord(String domainName, DomainRecord domainRecord)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns the specified domain record.
   *
   * @param domainName of the domain
   * @param recordId of the domain
   * @return {@link DomainRecord}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.1
   */
  DomainRecord getDomainRecordInfo(String domainName, Integer recordId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * method edits an existing domain record of the given domain.
   *
   * @param domainName of the domain
   * @param recordId of the domain
   * @param domainRecord the domain record values domain Id, record type, data, name, priority,
   *     port, weight
   * @return {@link DomainRecord}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  DomainRecord updateDomainRecord(String domainName, Integer recordId, DomainRecord domainRecord)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes the specified domain record from domain.
   *
   * @param domainName of the domain
   * @param recordId of the domain
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.1
   */
  Delete deleteDomainRecord(String domainName, Integer recordId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // SSH Key manipulation methods
  // ===========================================

  /**
   * Method lists all the available public SSH keys in your account that can be added to a droplet.
   *
   * @param pageNo for pagination
   * @return {@link Keys}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.2
   */
  Keys getAvailableKeys(Integer pageNo) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method shows a specific public SSH key information from your account that can be added to a
   * droplet.
   *
   * @param sshKeyId the SSH key Id
   * @return {@link Key}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.2
   */
  Key getKeyInfo(Integer sshKeyId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method shows a specific public SSH key information from your account that can be added to a
   * droplet.
   *
   * @param fingerprint the SSH key fingerprint
   * @return {@link Key}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Key getKeyInfo(String fingerprint) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to add a new public SSH key to your account
   *
   * @param newKey the {@link Key} object with sshKeyName and sshPublicKey
   * @return {@link Key}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.2
   */
  Key createKey(Key newKey) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to modify an existing SSH key in your account.
   *
   * @param sshKeyId the SSH key Id
   * @param newSshKeyName the new name to give the SSH key
   * @return {@link Key}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.2
   */
  Key updateKey(Integer sshKeyId, String newSshKeyName)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to modify an existing SSH key in your account.
   *
   * @param fingerprint the SSH fingerprint
   * @param newSshKeyName the new name to give the SSH key
   * @return {@link Key}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Key updateKey(String fingerprint, String newSshKeyName)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will delete the SSH key from your account.
   *
   * @param sshKeyId the SSH key Id, you would like to delete
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v1.2
   */
  Delete deleteKey(Integer sshKeyId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will delete the SSH key from your account.
   *
   * @param fingerprint the SSH fingerprint
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.0
   */
  Delete deleteKey(String fingerprint) throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Floating IP manipulation methods
  // ===========================================

  /**
   * Method will list all of the Floating IPs available from your account.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link FloatingIPs}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  FloatingIPs getAvailableFloatingIPs(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method creates a new Floating IP and assigns to the Droplet.
   *
   * @param dropletId the id of the droplet
   * @return {@link FloatingIP}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  FloatingIP createFloatingIP(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method creates a new Floating IP and its reserved to a Region
   *
   * @param region name of the DigitalOcean region
   * @return {@link FloatingIP}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  FloatingIP createFloatingIP(String region)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method retrieves the information about given Floating IP
   *
   * @param ipAddress Floating IP address
   * @return {@link FloatingIP}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  FloatingIP getFloatingIPInfo(String ipAddress)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes the Floating IP and removes it from your account.
   *
   * @param ipAddress Floating IP address
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Delete deleteFloatingIP(String ipAddress)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will assign Floating IP to a Droplet.
   *
   * @param dropletId the id of the droplet
   * @param ipAddress Floating IP address
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Action assignFloatingIP(Integer dropletId, String ipAddress)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will unassign Floating IP from a Droplet. The Floating IP will be reserved in the region
   * but not assigned to a Droplet.
   *
   * @param ipAddress Floating IP address
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.3
   */
  Action unassignFloatingIP(String ipAddress)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Tags manipulation methods
  // ===========================================
  /**
   * Method will list all of the Tags available from your account.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Tags}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.5
   */
  Tags getAvailableTags(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will create a Tag on DigitalOcean aacount.
   *
   * @param name Tag Name
   * @return {@link Tag}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.5
   */
  Tag createTag(String name) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method retrieves the Tag from DigitalOcean account.
   *
   * @param name Tag Name
   * @return {@link Tag}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.5
   */
  Tag getTag(String name) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes the existing Tag from DigitalOcean account.
   *
   * @param name Tag Name
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.5
   */
  Delete deleteTag(String name) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method tags a tag to given list of resources on DigitalOcean account.
   *
   * @param name Tag Name
   * @param resources list of resource by {@link Resource} objects
   * @return {@link Response}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.5
   */
  Response tagResources(String name, List<Resource> resources)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method untags a tag from given list of resources on DigitalOcean account.
   *
   * @param name Tag Name
   * @param resources list of resource by {@link Resource} objects
   * @return {@link Response}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.5
   */
  Response untagResources(String name, List<Resource> resources)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Volumes manipulation methods
  // ===========================================

  /**
   * Method will list all of the Volumes available from your account.
   *
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Volumes}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Volumes getAvailableVolumes(String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method creates new volume with given details
   *
   * @param volume details to create new volume
   * @return {@link Volume}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Volume createVolume(Volume volume) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method shows specific volume information by identifier
   *
   * @param volumeId volume identifier
   * @return {@link Volume}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Volume getVolumeInfo(String volumeId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method shows volume information by name and region slug
   *
   * @param volumeName name of the volume
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Volumes}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Volumes getVolumeInfo(String volumeName, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes volume by identifier
   *
   * @param volumeId volume identifier
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Delete deleteVolume(String volumeId) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes volume by name and region slug
   *
   * @param volumeName name of the volume
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Delete deleteVolume(String volumeName, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method attaches the given volume into droplet by identifier
   *
   * @param dropletId droplet identifier
   * @param volumeId volume identifier
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   */
  Action attachVolume(Integer dropletId, String volumeId, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method attaches the given volume into droplet by name
   *
   * @param dropletId droplet identifier
   * @param volumeName name of the volume
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Action attachVolumeByName(Integer dropletId, String volumeName, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method detaches volume from the droplet by identifier
   *
   * @param dropletId droplet identifier
   * @param volumeId volume identifier
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Action detachVolume(Integer dropletId, String volumeId, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method detaches volume from the droplet by volume name
   *
   * @param dropletId droplet identifier
   * @param volumeName name of the volume
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Action detachVolumeByName(Integer dropletId, String volumeName, String regionSlug)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method resizes volume by identifier
   *
   * @param volumeId volume identifier
   * @param regionSlug is code name of the region aka DigitalOcean data centers
   * @param sizeGigabytes size value in GB
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Action resizeVolume(String volumeId, String regionSlug, Double sizeGigabytes)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method will get all the available volume action by volume identifier
   *
   * @param volumeId volume identifier
   * @return {@link Actions}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Actions getAvailableVolumeActions(String volumeId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns specific volume action by action and volume identifier
   *
   * @param volumeId volume identifier
   * @param actionId the id of action
   * @return {@link Action}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.7
   */
  Action getVolumeAction(String volumeId, Integer actionId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method return all of the snapshots for given volume Id
   *
   * @param volumeId volume identifier
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Snapshots}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Snapshots getVolumeSnapshots(String volumeId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method take snapshot of given volume Id
   *
   * @param volumeId volume identifier
   * @param snapshotName the name the snapshot to be created
   * @return {@link Snapshot}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Snapshot takeVolumeSnapshot(String volumeId, String snapshotName)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Snapshots manipulation methods
  // ===========================================

  /**
   * Method return all of the snapshots available on your account
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Snapshots}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Snapshots getAvailableSnapshots(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method return all of the droplet snapshots available on your account
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Snapshots}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Snapshots getAllDropletSnapshots(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method return all of the volume snapshots available on your account
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Snapshots}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Snapshots getAllVolumeSnapshots(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns specific snapshot info by id
   *
   * @param snapshotId for snapshot
   * @return {@link Snapshot}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Snapshot getSnaphotInfo(String snapshotId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method deletes snapshot by id
   *
   * @param snapshotId for snapsho
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.8
   */
  Delete deleteSnapshot(String snapshotId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Load balancers manipulation methods
  // ===========================================

  /**
   * Method allows you to add a new load balancer to distribute traffic across multiple Droplets.
   *
   * <p>The LoadBalancer object passed in param can have a list of dropletIds set as dropletIds
   * attribute. In this case, given Droplets will be assigned to the Load Balancer.
   *
   * <p>You may also use a Droplet tag to assign a group of Droplets to Load Balancer in place of a
   * list of Droplet IDs. In this case, set the tag attribute of the LoadBalancer object passed in
   * param.
   *
   * @param loadBalancer the instance of the loadBalancer class
   * @return {@link LoadBalancer}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  LoadBalancer createLoadBalancer(LoadBalancer loadBalancer)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns complete information for given load balancer ID.
   *
   * @param loadBalancerId the id of the droplet
   * @return {@link LoadBalancer}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  LoadBalancer getLoadBalancerInfo(String loadBalancerId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all active loadbalancers that are currently running in your account. All
   * available API information is presented for each loadbalancer.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link LoadBalancers}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  LoadBalancers getAvailableLoadBalancers(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to update an existign load balancer. The LoadBalancer object passed in param
   * should contain a full representation of the Load Balancer including existing attributes. It may
   * contain one of the dropletIds or tag parameter as they are mutually exclusive. Note that any
   * attribute that is not provided will be reset to its default value.
   *
   * @param loadBalancer the instance of the loadBalancer class
   * @return {@link LoadBalancer}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  LoadBalancer updateLoadBalancer(LoadBalancer loadBalancer)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to assign a Droplet to a Load Balancer instance.
   *
   * @param loadBalancerId the id of the loadBalancer
   * @param dropletIds an array containing the IDs of the Droplets to be assigned to the Load
   *     Balancer instance.
   * @return {@link Response}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  Response addDropletsToLoadBalancer(String loadBalancerId, List<Integer> dropletIds)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to remove a Droplet from a Load Balancer instance.
   *
   * @param loadBalancerId the id of the loadBalancer
   * @param dropletIds an array containing the IDs of the Droplets to be removed from the Load
   *     Balancer instance.
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  Delete removeDropletsFromLoadBalancer(String loadBalancerId, List<Integer> dropletIds)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to add an additional forwarding rule to a Load Balancer instance.
   *
   * @param loadBalancerId the id of the loadBalancer
   * @param forwardingRules an array containing the Forwarding Rules to add to the Load Balancer
   *     instance.
   * @return {@link Response}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  Response addForwardingRulesToLoadBalancer(
      String loadBalancerId, List<ForwardingRules> forwardingRules)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to remove forwarding rules from a Load Balancer instance.
   *
   * @param loadBalancerId the id of the loadBalancer
   * @param forwardingRules an array containing the Forwarding Rules to remove from the Load
   *     Balancer instance.
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  Delete removeForwardingRulesFromLoadBalancer(
      String loadBalancerId, List<ForwardingRules> forwardingRules)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to delete a Load Balancer instance, disassociating any Droplets assigned to
   * it and removing it from your account.
   *
   * @param loadBalancerId the id of the loadBalancer
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.11
   */
  Delete deleteLoadBalancer(String loadBalancerId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Certificates manipulation methods
  // ===========================================

  /**
   * Method returns all available Certificates from your account.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link LoadBalancers}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.12
   */
  Certificates getAvailableCertificates(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to create a new certificate. See the required parameters section below for an
   * explanation of the variables that are needed to create a new certificate.
   *
   * <p>Create a instance of {@link Certificate} class and populated the certificate object
   * appropriately. Required values are -
   *
   * <pre>
   * {
   *    "name": "web-cert-01",
   *    "private_key": "-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----",
   *    "leaf_certificate": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
   *    "certificate_chain": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"
   * }
   * </pre>
   *
   * @param certificate the instance of the Certificate class
   * @return {@link Certificate}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.12
   */
  Certificate createCertificate(Certificate certificate)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to create a new Let's Encrypt certificate. See the required parameters
   * section below for an explanation of the variables that are needed to create a new Let's Encrypt
   * certificate.
   *
   * <p>Create a instance of {@link Certificate} class and populated the certificate object
   * appropriately. Required values are -
   *
   * <pre>
   * {
   *    "name": "le-cert-01",
   *    "type": "lets_encrypt",
   *    "dns_names": ["www.example.com","example.com"]
   * }
   * </pre>
   *
   * @param certificate the instance of the Certificate class
   * @return {@link Certificate}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.12
   */
  Certificate createLetsEncryptCertificate(Certificate certificate)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns the Certificate information for given certificate ID.
   *
   * @param certificateId the id of the certificate
   * @return {@link Certificate}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.12
   */
  Certificate getCertificateInfo(String certificateId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to delete a Certificate by Id from your account.
   *
   * @param certificateId the id of the certificate
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.12
   */
  Delete deleteCertificate(String certificateId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  // ===========================================
  // Firewalls manipulation methods
  // ===========================================

  /**
   * Method allows you to add a new firewall to restrict network access to and from a Droplet.
   *
   * <p>The Firewall object passed in param can have a list of dropletIds set as dropletIds
   * attribute. In this case, given Droplets will use the Firewall rules.
   *
   * <p>You may also use a Droplet tag to assign a group of Droplets to use the Firewall in place of
   * a list of Droplet IDs. In this case, set the tag attribute of the Firewall object passed in
   * param.
   *
   * @param firewall the instance of the firewall class
   * @return {@link Firewall}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.16
   */
  Firewall createFirewall(Firewall firewall)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns complete information for given firewall ID.
   *
   * @param firewallId the id of the firewall
   * @return {@link Firewall}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.16
   */
  Firewall getFirewallInfo(String firewallId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to update an existing fireawll. The Firewall object passed in param should
   * contain a full representation of the Firewall including existing attributes. It may contain one
   * of the dropletIds or tag parameter as they are mutually exclusive. Note that any attribute that
   * is not provided will be reset to its default value.
   *
   * @param firewall the instance of the firewall class
   * @return {@link Firewall}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.16
   */
  Firewall updateFirewall(Firewall firewall)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to delete a Firewall instance, disassociating any Droplets assigned to it and
   * removing it from your account.
   *
   * @param firewallId the id of the firewall
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.16
   */
  Delete deleteFirewall(String firewallId)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to assign a {@link Droplet} to a {@link Firewall} instance.
   *
   * @param firewallId the id of the firewall to add droplets to
   * @param dropletIds the list of of droplet IDs to add to the firewall
   * @return {@link Response} A generic HTTP status response
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.17
   */
  Response addDropletsToFirewall(String firewallId, List<Integer> dropletIds)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to remove a Droplet from a Load Balancer instance.
   *
   * @param firewallId the id of the firewall
   * @param dropletIds the list of droplet IDs to be removed from the firewall instance.
   * @return {@link Delete}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.17
   */
  Delete removeDropletsFromFirewall(String firewallId, List<Integer> dropletIds)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method returns all available firewalls that are currently running in your account. All
   * available API information is presented for each firewall.
   *
   * @param pageNo for pagination
   * @param perPage no. of items per page
   * @return {@link Firewalls}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   * @since v2.16
   */
  Firewalls getAvailableFirewalls(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to create a new project.
   *
   * @param project the project
   * @return {@link Project}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   */
  Project createProject(Project project) throws DigitalOceanException, RequestUnsuccessfulException;

  /**
   * Method allows you to get all the projects.
   *
   * @return {@link Projects}
   * @throws DigitalOceanException if request had interruption [ <code>
   *     HTTP status code &gt;= 400 &amp;&amp; &lt; 510</code>]
   * @throws RequestUnsuccessfulException if any RESTful request unsuccessful from wrapper method
   */
  Projects getAvailableProjects() throws DigitalOceanException, RequestUnsuccessfulException;

  Project updateProject(Project project) throws DigitalOceanException, RequestUnsuccessfulException;

  Project patchProject(Project project) throws DigitalOceanException, RequestUnsuccessfulException;

  Project getProject(String projectId) throws DigitalOceanException, RequestUnsuccessfulException;

  Project getDefaultProject() throws DigitalOceanException, RequestUnsuccessfulException;

  Project updateDefaultProject(Project project)
      throws DigitalOceanException, RequestUnsuccessfulException;

  Project patchDefaultProject(Project project)
      throws DigitalOceanException, RequestUnsuccessfulException;

  Delete deleteProject(String projectId) throws DigitalOceanException, RequestUnsuccessfulException;
} public enum ActionType {
  @SerializedName("create")
  CREATE("create"),

  @SerializedName("reboot")
  REBOOT("reboot"),

  @SerializedName("power_cycle")
  POWER_CYCLE("power_cycle"),

  @SerializedName("shutdown")
  SHUTDOWN("shutdown"),

  @SerializedName("power_off")
  POWER_OFF("power_off"),

  @SerializedName("power_on")
  POWER_ON("power_on"),

  @SerializedName("password_reset")
  PASSWORD_RESET("password_reset"),

  @SerializedName("resize")
  RESIZE("resize"),

  @SerializedName("restore")
  RESTORE("restore"),

  @SerializedName("rebuild")
  REBUILD("rebuild"),

  @SerializedName("rename")
  RENAME("rename"),

  @SerializedName("change_kernel")
  CHANGE_KERNEL("change_kernel"),

  @SerializedName("enable_ipv6")
  ENABLE_IPV6("enable_ipv6"),

  @SerializedName("enable_backups")
  ENABLE_BACKUPS("enable_backups"),

  @SerializedName("disable_backups")
  DISABLE_BACKUPS("disable_backups"),

  @SerializedName("enable_private_networking")
  ENABLE_PRIVATE_NETWORKING("enable_private_networking"),

  @SerializedName("snapshot")
  SNAPSHOT("snapshot"),

  @SerializedName("backup")
  BACKUP("backup"),

  @SerializedName("transfer")
  TRANSFER("transfer"),

  @SerializedName("convert")
  CONVERT("convert"),

  @SerializedName("convert_to_snapshot")
  CONVERT_TO_SNAPSHOT("convert_to_snapshot"),

  @SerializedName("distribution")
  DISTRIBUTION("distribution"),

  @SerializedName("application")
  APPLICATION("application"),

  @SerializedName("assign_ip")
  ASSIGN_FLOATING_IP("assign_ip"),

  @SerializedName("unassign_ip")
  UNASSIGN_FLOATING_IP("unassign_ip"),

  @SerializedName("reserve_ip")
  RESERVE_FLOATING_IP("reserve_ip"),

  @SerializedName(
      value = "attach",
      alternate = {"attach_volume"})
  ATTACH("attach"),

  @SerializedName(
      value = "detach",
      alternate = {"detach_volume"})
  DETACH("detach");

  private String value;

  private ActionType(String value) {
    this.value = value;
  }

  @Override
  public String toString() {
    return this.value;
  }

  public static ActionType fromValue(String value) {
    if (StringUtils.isBlank(value)) {
      throw new IllegalArgumentException("Value cannot be null or empty!");
    }

    for (ActionType dat : ActionType.values()) {
      if (value.equalsIgnoreCase(dat.value)) {
        return dat;
      }
    }

    throw new IllegalArgumentException("Cannot create enum from " + value + " value!");
  }
} public enum ApiAction {

  // Droplet
  AVAILABLE_DROPLETS("/droplets", "droplets", RequestMethod.GET, Droplets.class),
  GET_DROPLETS_KERNELS("/droplets/%s/kernels", "kernels", RequestMethod.GET, Kernels.class),
  GET_DROPLET_SNAPSHOTS("/droplets/%s/snapshots", "snapshots", RequestMethod.GET, Snapshots.class),
  GET_DROPLET_BACKUPS("/droplets/%s/backups", "backups", RequestMethod.GET, Backups.class),
  GET_DROPLET_NEIGHBORS("/droplets/%s/neighbors", "droplets", RequestMethod.GET, Droplets.class),
  GET_DROPLET_INFO("/droplets/%s", "droplet", RequestMethod.GET, Droplet.class),
  CREATE_DROPLET("/droplets", "droplet", RequestMethod.POST, Droplet.class),
  CREATE_DROPLETS("/droplets", "droplets", RequestMethod.POST, Droplets.class),
  DELETE_DROPLET("/droplets/%s", "response", RequestMethod.DELETE, Delete.class),
  DELETE_DROPLET_BY_TAG_NAME("/droplets", "response", RequestMethod.DELETE, Delete.class),
  REBOOT_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  POWER_CYCLE_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  SHUTDOWN_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  POWER_OFF_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  POWER_ON_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  RESET_DROPLET_PASSWORD("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  RESIZE_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  RESTORE_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  REBUILD_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  RENAME_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  CHANGE_DROPLET_KERNEL("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  ENABLE_DROPLET_IPV6("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  ENABLE_DROPLET_BACKUPS("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  DISABLE_DROPLET_BACKUPS("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  ENABLE_DROPLET_PRIVATE_NETWORKING(
      "/droplets/%s/actions", "action", RequestMethod.POST, Action.class),
  SNAPSHOT_DROPLET("/droplets/%s/actions", "action", RequestMethod.POST, Action.class),

  // Account
  GET_ACCOUNT_INFO("/account", "account", RequestMethod.GET, Account.class),

  // Reports
  ALL_DROPLET_NEIGHBORS(
      "/reports/droplet_neighbors", "neighbors", RequestMethod.GET, Neighbors.class),

  // Action
  AVAILABLE_ACTIONS("/actions", "actions", RequestMethod.GET, Actions.class),
  GET_ACTION_INFO("/actions/%s", "action", RequestMethod.GET, Action.class),
  GET_DROPLET_ACTIONS("/droplets/%s/actions", "actions", RequestMethod.GET, Actions.class),
  GET_IMAGE_ACTIONS("/images/%s/actions", "actions", RequestMethod.GET, Actions.class),
  GET_FLOATING_IP_ACTIONS("/floating_ips/%s/actions", "actions", RequestMethod.GET, Actions.class),
  GET_FLOATING_IP_ACTION_INFO(
      "/floating_ips/%s/actions/%s", "action", RequestMethod.GET, Action.class),
  GET_VOLUME_ACTIONS("/volumes/%s/actions", "actions", RequestMethod.GET, Actions.class),
  GET_VOLUME_ACTION("/volumes/%s/actions/%s", "action", RequestMethod.GET, Action.class),

  // Image
  AVAILABLE_IMAGES("/images", "images", RequestMethod.GET, Images.class),
  GET_IMAGE_INFO("/images/%s", "image", RequestMethod.GET, Image.class),
  CREATE_CUSTOM_IMAGE("/images", "image", RequestMethod.POST, Image.class),
  UPDATE_IMAGE_INFO("/images/%s", "image", RequestMethod.PUT, Image.class),
  DELETE_IMAGE("/images/%s", "response", RequestMethod.DELETE, Delete.class),
  TRANSFER_IMAGE("/images/%s/actions", "action", RequestMethod.POST, Action.class),
  CONVERT_IMAGE("/images/%s/actions", "action", RequestMethod.POST, Action.class),

  // Region
  AVAILABLE_REGIONS("/regions", "regions", RequestMethod.GET, Regions.class),

  // Size
  AVAILABLE_SIZES("/sizes", "sizes", RequestMethod.GET, Sizes.class),

  // Domain
  AVAILABLE_DOMAINS("/domains", "domains", RequestMethod.GET, Domains.class),
  GET_DOMAIN_INFO("/domains/%s", "domain", RequestMethod.GET, Domain.class),
  CREATE_DOMAIN("/domains", "domain", RequestMethod.POST, Domain.class),
  DELETE_DOMAIN("/domains/%s", "response", RequestMethod.DELETE, Delete.class),

  // Domain Record
  GET_DOMAIN_RECORDS(
      "/domains/%s/records", "domain_records", RequestMethod.GET, DomainRecords.class),
  GET_DOMAIN_RECORD_INFO(
      "/domains/%s/records/%s", "domain_record", RequestMethod.GET, DomainRecord.class),
  CREATE_DOMAIN_RECORD(
      "/domains/%s/records", "domain_record", RequestMethod.POST, DomainRecord.class),
  UPDATE_DOMAIN_RECORD(
      "/domains/%s/records/%s", "domain_record", RequestMethod.PUT, DomainRecord.class),
  DELETE_DOMAIN_RECORD("/domains/%s/records/%s", "response", RequestMethod.DELETE, Delete.class),

  // Key
  AVAILABLE_KEYS("/account/keys", "ssh_keys", RequestMethod.GET, Keys.class),
  GET_KEY_INFO("/account/keys/%s", "ssh_key", RequestMethod.GET, Key.class),
  CREATE_KEY("/account/keys", "ssh_key", RequestMethod.POST, Key.class),
  UPDATE_KEY("/account/keys/%s", "ssh_key", RequestMethod.PUT, Key.class),
  DELETE_KEY("/account/keys/%s", "response", RequestMethod.DELETE, Delete.class),

  // Floating IP
  FLOATING_IPS("/floating_ips", "floating_ips", RequestMethod.GET, FloatingIPs.class),
  CREATE_FLOATING_IP("/floating_ips", "floating_ip", RequestMethod.POST, FloatingIP.class),
  GET_FLOATING_IP_INFO("/floating_ips/%s", "floating_ip", RequestMethod.GET, FloatingIP.class),
  DELETE_FLOATING_IP("/floating_ips/%s", "response", RequestMethod.DELETE, Delete.class),
  ASSIGN_FLOATING_IP("/floating_ips/%s/actions", "action", RequestMethod.POST, Action.class),
  UNASSIGN_FLOATING_IP("/floating_ips/%s/actions", "action", RequestMethod.POST, Action.class),

  // Tags
  AVAILABLE_TAGS("/tags", "tags", RequestMethod.GET, Tags.class),
  CREATE_TAG("/tags", "tag", RequestMethod.POST, Tag.class),
  GET_TAG("/tags/%s", "tag", RequestMethod.GET, Tag.class),
  DELETE_TAG("/tags/%s", "response", RequestMethod.DELETE, Delete.class),
  TAG_RESOURCE("/tags/%s/resources", "response", RequestMethod.POST, Response.class),
  UNTAG_RESOURCE("/tags/%s/resources", "response", RequestMethod.DELETE, Response.class),

  // Volumes
  AVAILABLE_VOLUMES("/volumes", "volumes", RequestMethod.GET, Volumes.class),
  CREATE_VOLUME("/volumes", "volume", RequestMethod.POST, Volume.class),
  GET_VOLUME_INFO("/volumes/%s", "volume", RequestMethod.GET, Volume.class),
  GET_VOLUME_INFO_BY_NAME("/volumes", "volumes", RequestMethod.GET, Volumes.class),
  DELETE_VOLUME("/volumes/%s", "response", RequestMethod.DELETE, Delete.class),
  DELETE_VOLUME_BY_NAME("/volumes", "response", RequestMethod.DELETE, Delete.class),
  ACTIONS_VOLUME("/volumes/%s/actions", "action", RequestMethod.POST, Action.class),
  ACTIONS_VOLUME_BY_NAME("/volumes/actions", "action", RequestMethod.POST, Action.class),
  GET_VOLUME_SNAPSHOTS("/volumes/%s/snapshots", "snapshots", RequestMethod.GET, Snapshots.class),
  SNAPSHOT_VOLUME("/volumes/%s/snapshots", "snapshot", RequestMethod.POST, Snapshot.class),

  // Snapshots
  AVAILABLE_SNAPSHOTS("/snapshots", "snapshots", RequestMethod.GET, Snapshots.class),
  ALL_DROPLET_SNAPSHOTS("/snapshots", "snapshots", RequestMethod.GET, Snapshots.class),
  ALL_VOLUME_SNAPSHOTS("/snapshots", "snapshots", RequestMethod.GET, Snapshots.class),
  GET_SNAPSHOT_INFO("/snapshots/%s", "snapshot", RequestMethod.GET, Snapshot.class),
  DELETE_SNAPSHOT("/snapshots/%s", "response", RequestMethod.DELETE, Delete.class),

  // Projects
  CREATE_PROJECT("/projects", "project", RequestMethod.POST, Project.class),
  GET_ALL_PROJECTS("/projects", "projects", RequestMethod.GET, Projects.class),
  UPDATE_PROJECT("/projects/%s", "project", RequestMethod.PUT, Project.class),
  PATCH_PROJECT("/projects/%s", "project", RequestMethod.PATCH, Project.class),
  GET_PROJECT("/projects/%s", "project", RequestMethod.GET, Project.class),
  GET_DEFAULT_PROJECT("/projects/default", "project", RequestMethod.GET, Project.class),
  UPDATE_DEFAULT_PROJECT("/projects/default", "project", RequestMethod.PUT, Project.class),
  PATCH_DEFAULT_PROJECT("/projects/default", "project", RequestMethod.PATCH, Project.class),
  DELETE_PROJECT("/projects/%s", "response", RequestMethod.DELETE, Delete.class),

  // Load Balancers
  CREATE_LOAD_BALANCER("/load_balancers", "load_balancer", RequestMethod.POST, LoadBalancer.class),
  GET_LOAD_BALANCER_INFO(
      "/load_balancers/%s", "load_balancer", RequestMethod.GET, LoadBalancer.class),
  AVAILABLE_LOAD_BALANCERS(
      "/load_balancers", "load_balancers", RequestMethod.GET, LoadBalancers.class),
  UPDATE_LOAD_BALANCER(
      "/load_balancers/%s", "load_balancer", RequestMethod.PUT, LoadBalancer.class),
  ADD_DROPLET_TO_LOAD_BALANCER(
      "/load_balancers/%s/droplets", "response", RequestMethod.POST, Response.class),
  REMOVE_DROPLET_FROM_LOAD_BALANCER(
      "/load_balancers/%s/droplets", "response", RequestMethod.DELETE, Delete.class),
  ADD_FORWARDING_RULES_TO_LOAD_BALANCER(
      "/load_balancers/%s/forwarding_rules", "response", RequestMethod.POST, Response.class),
  REMOVE_FORWARDING_RULES_FROM_LOAD_BALANCER(
      "/load_balancers/%s/forwarding_rules", "response", RequestMethod.DELETE, Delete.class),
  DELETE_LOAD_BALANCER("/load_balancers/%s", "response", RequestMethod.DELETE, Delete.class),

  // Certificates
  AVAILABLE_CERTIFICATES("/certificates", "certificates", RequestMethod.GET, Certificates.class),
  GET_CERTIFICATE_INFO("/certificates/%s", "certificate", RequestMethod.GET, Certificate.class),
  CREATE_CERTIFICATE("/certificates", "certificate", RequestMethod.POST, Certificate.class),
  DELETE_CERTIFICATE("/certificates/%s", "response", RequestMethod.DELETE, Delete.class),

  // Firewalls
  CREATE_FIREWALL("/firewalls", "firewall", RequestMethod.POST, Firewall.class),
  GET_FIREWALL_INFO("/firewalls/%s", "firewall", RequestMethod.GET, Firewall.class),
  UPDATE_FIREWALL("/firewalls/%s", "firewall", RequestMethod.PUT, Firewall.class),
  DELETE_FIREWALL("/firewalls/%s", "response", RequestMethod.DELETE, Delete.class),
  AVAILABLE_FIREWALLS("/firewalls", "firewalls", RequestMethod.GET, Firewalls.class),
  ADD_DROPLET_TO_FIREWALL("/firewalls/%s/droplets", "response", RequestMethod.POST, Response.class),
  REMOVE_DROPLET_FROM_FIREWALL(
      "/firewalls/%s/droplets", "response", RequestMethod.DELETE, Delete.class);

  private String path;

  private String elementName;

  private RequestMethod method;

  private Class<?> clazz;

  ApiAction(String path, RequestMethod method) {
    this(path, null, method);
  }

  ApiAction(String path, String elementName) {
    this(path, elementName, RequestMethod.GET);
  }

  ApiAction(String path, String elementName, RequestMethod method) {
    this(path, elementName, method, null);
  }

  ApiAction(String path, String elementName, RequestMethod method, Class<?> clazz) {
    this.path = path;
    this.elementName = elementName;
    this.method = method;
    this.clazz = clazz;
  }

  /** @return the path */
  public String getPath() {
    return path;
  }

  /** @return the elementName */
  public String getElementName() {
    return elementName;
  }

  /** @return the method */
  public RequestMethod getMethod() {
    return method;
  }

  /** @return the clazz */
  public Class<?> getClazz() {
    return clazz;
  }
} public interface Constants {

  // General
  String UTF_8 = "utf-8";
  Integer START_PAGE_NO = 1;
  String URL_PATH_SEPARATOR = "/";
  String USER_AGENT = "DigitalOcean API Client by myjeeva.com";
  String JSON_CONTENT_TYPE = "application/json";
  String FORM_URLENCODED_CONTENT_TYPE = "application/x-www-form-urlencoded";
  String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX";
  String RATE_LIMIT_JSON_STRUCT =
      "\"rate_limit\": { \"limit\": %s, \"remaining\": %s, \"reset\": \"%s\"}";
  String RATE_LIMIT_ELEMENT_NAME = "rate_limit";
  String LINKS_ELEMENT_NAME = "links";
  String META_ELEMENT_NAME = "meta";

  // HTTPS Scheme
  String HTTPS_SCHEME = "https";

  // HTTP Param name
  String PARAM_PAGE_NO = "page";
  String PARAM_PER_PAGE = "per_page";
  int DEFAULT_PAGE_SIZE = 25; // per DO doc

  String NO_CONTENT_JSON_STRUCT = "{\"response\": {\"request_status\": true, \"status_code\": %s}}";

  // HTTP Headers
  String HDR_USER_AGENT = "X-User-Agent";
  String HDR_CONTENT_TYPE = HttpHeaders.CONTENT_TYPE;
  String HDR_AUTHORIZATION = HttpHeaders.AUTHORIZATION;
  String HDR_RATE_LIMIT = "RateLimit-Limit";
  String HDR_RATE_REMAINING = "RateLimit-Remaining";
  String HDR_RATE_RESET = "RateLimit-Reset";
} public enum RequestMethod {
  GET,
  POST,
  PUT,
  DELETE,
  PATCH;
} public class DigitalOceanException extends Exception {

  static final long serialVersionUID = -925220451573356906L;

  private String id;

  private int httpStatusCode;

  public DigitalOceanException(String msg) {
    super(msg);
  }

  public DigitalOceanException(String msg, Throwable t) {
    super(msg, t);
  }

  public DigitalOceanException(String msg, String id, int statusCode) {
    super(msg);
    this.id = id;
    this.httpStatusCode = statusCode;
  }

  /** @return the id */
  public String getId() {
    return id;
  }

  /** @return the httpStatusCode */
  public int getHttpStatusCode() {
    return httpStatusCode;
  }
} public class RequestUnsuccessfulException extends Exception {

  private static final long serialVersionUID = 6949447731150358499L;

  public RequestUnsuccessfulException(String msg) {
    super(msg);
  }

  public RequestUnsuccessfulException(String msg, Throwable t) {
    super(msg, t);
  }
} public class CustomHttpDelete extends HttpPost {

  public CustomHttpDelete(URI uri) {
    super(uri);
  }

  public CustomHttpDelete(String url) {
    super(url);
  }

  @Override
  public String getMethod() {
    return "DELETE";
  }
} public class Account extends Base {

  private static final long serialVersionUID = 5951525501167424430L;

  private String email;

  private String uuid;

  @SerializedName("droplet_limit")
  private Integer dropletLimit;

  @SerializedName("email_verified")
  private boolean isEmailVerified;

  private String status;

  @SerializedName("status_message")
  private String statusMessage;

  @SerializedName("floating_ip_limit")
  private Integer floatingIPLimit;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the email */
  public String getEmail() {
    return email;
  }

  /** @param email the email to set */
  public void setEmail(String email) {
    this.email = email;
  }

  /** @return the uuid */
  public String getUuid() {
    return uuid;
  }

  /** @param uuid the uuid to set */
  public void setUuid(String uuid) {
    this.uuid = uuid;
  }

  /** @return the dropletLimit */
  public Integer getDropletLimit() {
    return dropletLimit;
  }

  /** @param dropletLimit the dropletLimit to set */
  public void setDropletLimit(Integer dropletLimit) {
    this.dropletLimit = dropletLimit;
  }

  /** @return the isEmailVerified */
  public boolean isEmailVerified() {
    return isEmailVerified;
  }

  /** @param isEmailVerified the isEmailVerified to set */
  public void setEmailVerified(boolean isEmailVerified) {
    this.isEmailVerified = isEmailVerified;
  }

  /** @return the status */
  public String getStatus() {
    return status;
  }

  /** @param status the status to set */
  public void setStatus(String status) {
    this.status = status;
  }

  /** @return the statusMessage */
  public String getStatusMessage() {
    return statusMessage;
  }

  /** @param statusMessage the statusMessage to set */
  public void setStatusMessage(String statusMessage) {
    this.statusMessage = statusMessage;
  }

  /** @return the floatingIPLimit */
  public Integer getFloatingIPLimit() {
    return floatingIPLimit;
  }

  /** @param floatingIPLimit the floatingIPLimit to set */
  public void setFloatingIPLimit(Integer floatingIPLimit) {
    this.floatingIPLimit = floatingIPLimit;
  }
} public class Action extends Base {

  private static final long serialVersionUID = 5951525501167424430L;

  private Integer id;

  @SerializedName("resource_id")
  private Long resourceId;

  private ActionStatus status;

  private ActionType type;

  @SerializedName("resource_type")
  private ResourceType resourceType;

  @SerializedName("started_at")
  private Date startedAt;

  @SerializedName("completed_at")
  private Date completedAt;

  private Region region;

  @SerializedName("region_slug")
  private String regionSlug;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the id */
  public Integer getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(Integer id) {
    this.id = id;
  }

  /** @return the resourceId */
  public Long getResourceId() {
    return resourceId;
  }

  /** @param resourceId the resourceId to set */
  public void setResourceId(Long resourceId) {
    this.resourceId = resourceId;
  }

  /** @return the status */
  public ActionStatus getStatus() {
    return status;
  }

  /** @param status the status to set */
  public void setStatus(ActionStatus status) {
    this.status = status;
  }

  /** @return the type */
  public ActionType getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(ActionType type) {
    this.type = type;
  }

  /** @return the resourceType */
  public ResourceType getResourceType() {
    return resourceType;
  }

  /** @param resourceType the resourceType to set */
  public void setResourceType(ResourceType resourceType) {
    this.resourceType = resourceType;
  }

  /** @return the startedAt */
  public Date getStartedAt() {
    return startedAt;
  }

  /** @param startedAt the startedAt to set */
  public void setStartedAt(Date startedAt) {
    this.startedAt = startedAt;
  }

  /** @return the completedAt */
  public Date getCompletedAt() {
    return completedAt;
  }

  /** @param completedAt the completedAt to set */
  public void setCompletedAt(Date completedAt) {
    this.completedAt = completedAt;
  }

  /** @return the region */
  public Region getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(Region region) {
    this.region = region;
  }

  /** @return the regionSlug */
  public String getRegionSlug() {
    return regionSlug;
  }

  /** @param regionSlug the regionSlug to set */
  public void setRegionSlug(String regionSlug) {
    this.regionSlug = regionSlug;
  }
} public class Actions extends Base {

  private static final long serialVersionUID = 7510681873537152716L;

  private List<Action> actions;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the actions */
  public List<Action> getActions() {
    return actions;
  }

  /** @param actions the actions to set */
  public void setActions(List<Action> actions) {
    this.actions = actions;
  }
} public class Backups extends Base {

  private static final long serialVersionUID = 1799833528333920392L;

  List<Backup> backups;

  /** @return the backups */
  public List<Backup> getBackups() {
    return backups;
  }

  /** @param backups the backups to set */
  public void setBackups(List<Backup> backups) {
    this.backups = backups;
  }
} public class Certificate extends Base {

  private static final long serialVersionUID = -7525532097995479493L;

  private String id;

  @Expose private String name;

  @SerializedName("not_after")
  private String notAfter;

  @SerializedName("sha1_fingerprint")
  private String sha1Fingerprint;

  @SerializedName("created_at")
  private Date createdDate;

  @Expose
  @SerializedName("private_key")
  private String privateKey;

  @Expose
  @SerializedName("leaf_certificate")
  private String leafCertificate;

  @Expose
  @SerializedName("certificate_chain")
  private String certificateChain;

  @Expose private CertificateState state;

  @Expose
  @SerializedName("dns_names")
  private List<String> dnsNames;

  @Expose private String type;

  /** Default Constructor. */
  public Certificate() {
    // default constructor
  }

  /**
   * Constructor for new certificate create request.
   *
   * @param name the name for the certificate
   * @param privateKey the private key
   * @param leafCertificate the leaf certificate
   * @param certificateChain the certificate chain
   */
  public Certificate(
      String name, String privateKey, String leafCertificate, String certificateChain) {
    this.name = name;
    this.privateKey = privateKey;
    this.leafCertificate = leafCertificate;
    this.certificateChain = certificateChain;
  }

  /**
   * Constructor for new Let's Encrypt certificate create request.
   *
   * @param name the name for the certificate
   * @param type the type of the certificate
   * @param dnsNames list of dns names
   */
  public Certificate(String name, String type, List<String> dnsNames) {
    this.name = name;
    this.type = type;
    this.dnsNames = dnsNames;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the id */
  public String getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(String id) {
    this.id = id;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the notAfter */
  public String getNotAfter() {
    return notAfter;
  }

  /** @param notAfter the notAfter to set */
  public void setNotAfter(String notAfter) {
    this.notAfter = notAfter;
  }

  /** @return the sha1Fingerprint */
  public String getSha1Fingerprint() {
    return sha1Fingerprint;
  }

  /** @param sha1Fingerprint the sha1Fingerprint to set */
  public void setSha1Fingerprint(String sha1Fingerprint) {
    this.sha1Fingerprint = sha1Fingerprint;
  }

  /** @return the createdDate */
  public Date getCreatedDate() {
    return createdDate;
  }

  /** @param createdDate the createdDate to set */
  public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
  }

  /** @return the privateKey */
  public String getPrivateKey() {
    return privateKey;
  }

  /** @param privateKey the privateKey to set */
  public void setPrivateKey(String privateKey) {
    this.privateKey = privateKey;
  }

  /** @return the leafCertificate */
  public String getLeafCertificate() {
    return leafCertificate;
  }

  /** @param leafCertificate the leafCertificate to set */
  public void setLeafCertificate(String leafCertificate) {
    this.leafCertificate = leafCertificate;
  }

  /** @return the certificateChain */
  public String getCertificateChain() {
    return certificateChain;
  }

  /** @param certificateChain the certificateChain to set */
  public void setCertificateChain(String certificateChain) {
    this.certificateChain = certificateChain;
  }

  /** @return the state */
  public CertificateState getState() {
    return state;
  }

  /** @param state the state to set */
  public void setState(CertificateState state) {
    this.state = state;
  }

  /** @return the dnsNames */
  public List<String> getDnsNames() {
    return dnsNames;
  }

  /** @param dnsNames the dnsNames to set */
  public void setDnsNames(List<String> dnsNames) {
    this.dnsNames = dnsNames;
  }

  /** @return the type */
  public String getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(String type) {
    this.type = type;
  }
} public class Certificates extends Base {

  private static final long serialVersionUID = -6122243268483320321L;

  private List<Certificate> certificates;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the certificates */
  public List<Certificate> getCertificates() {
    return certificates;
  }

  /** @param certificates the certificates to set */
  public void setCertificates(List<Certificate> certificates) {
    this.certificates = certificates;
  }
} public class Delete extends Response {

  private static final long serialVersionUID = -3552374545843268569L;

  /** Default Constructor */
  public Delete() {
    // Default Constructor
  }

  /**
   * Parameterized Constructor
   *
   * @param isRequestSuccess whether delete is success or not
   */
  public Delete(Boolean isRequestSuccess) {
    super(isRequestSuccess);
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }
} public class Domain extends Base {

  private static final long serialVersionUID = 5958407274594550472L;

  @Expose private String name;

  @SerializedName("ttl")
  private Integer timeToLive;

  @SerializedName("zone_file")
  private String zoneFile;

  @Expose
  @SerializedName("ip_address")
  private String ipAddress;

  public Domain() {
    // Default Constructor
  }

  public Domain(String name, String ipAddress) {
    this.name = name;
    this.ipAddress = ipAddress;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the timeToLive */
  public Integer getTimeToLive() {
    return timeToLive;
  }

  /** @param timeToLive the timeToLive to set */
  public void setTimeToLive(Integer timeToLive) {
    this.timeToLive = timeToLive;
  }

  /** @return the zoneFile */
  public String getZoneFile() {
    return zoneFile;
  }

  /** @param zoneFile the zoneFile to set */
  public void setZoneFile(String zoneFile) {
    this.zoneFile = zoneFile;
  }

  /** @return the ipAddress */
  public String getIpAddress() {
    return ipAddress;
  }

  /** @param ipAddress the ipAddress to set */
  public void setIpAddress(String ipAddress) {
    this.ipAddress = ipAddress;
  }
} public class DomainRecord extends Base {

  private static final long serialVersionUID = 5656335027984698525L;

  private Integer id;

  @Expose private String type;

  @Expose private String name;

  @Expose private String data;

  @Expose private Integer priority;

  @Expose private Integer port;

  @Expose private Integer weight;

  @Expose private Integer ttl;

  @Expose private Integer flags;

  @Expose private CaaTagType tag;

  public DomainRecord() {
    // Default Constructor
  }

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

  public DomainRecord(String name, String type) {
    this(name, null, type, null, null, null);
  }

  public DomainRecord(String name, String data, String type) {
    this(name, data, type, null, null, null);
  }

  public DomainRecord(
      String name, String data, String type, Integer priority, Integer port, Integer weight) {
    this(name, data, type, priority, null, null, null);
  }

  public DomainRecord(
      String name,
      String data,
      String type,
      Integer priority,
      Integer port,
      Integer weight,
      Integer ttl) {
    this.name = name;
    this.data = data;
    this.type = type;
    this.priority = priority;
    this.port = port;
    this.weight = weight;
    this.ttl = ttl;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the id */
  public Integer getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(Integer id) {
    this.id = id;
  }

  /** @return the type */
  public String getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(String type) {
    this.type = type;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the data */
  public String getData() {
    return data;
  }

  /** @param data the data to set */
  public void setData(String data) {
    this.data = data;
  }

  /** @return the priority */
  public Integer getPriority() {
    return priority;
  }

  /** @param priority the priority to set */
  public void setPriority(Integer priority) {
    this.priority = priority;
  }

  /** @return the port */
  public Integer getPort() {
    return port;
  }

  /** @param port the port to set */
  public void setPort(Integer port) {
    this.port = port;
  }

  /** @return the weight */
  public Integer getWeight() {
    return weight;
  }

  /** @param weight the weight to set */
  public void setWeight(Integer weight) {
    this.weight = weight;
  }

  /** @return the TTL, in seconds */
  public Integer getTtl() {
    return ttl;
  }

  /** @param ttl the TTL, in seconds */
  public void setTtl(Integer ttl) {
    this.ttl = ttl;
  }

  /** @return the flags */
  public Integer getFlags() {
    return flags;
  }

  /** @param flags the flags to set */
  public void setFlags(Integer flags) {
    this.flags = flags;
  }

  /** @return the tag */
  public CaaTagType getTag() {
    return tag;
  }

  /** @param tag the tag to set */
  public void setTag(CaaTagType tag) {
    this.tag = tag;
  }
} public class DomainRecords extends Base {

  private static final long serialVersionUID = -3070769129688315651L;

  @SerializedName("domain_records")
  private List<DomainRecord> domainRecords;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the domainRecords */
  public List<DomainRecord> getDomainRecords() {
    return domainRecords;
  }

  /** @param domainRecords the domainRecords to set */
  public void setDomainRecords(List<DomainRecord> domainRecords) {
    this.domainRecords = domainRecords;
  }
} public class Domains extends Base {

  private static final long serialVersionUID = 403429426585596826L;

  private List<Domain> domains;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the domains */
  public List<Domain> getDomains() {
    return domains;
  }

  /** @param domains the domains to set */
  public void setDomains(List<Domain> domains) {
    this.domains = domains;
  }
} public class Droplet extends Base {

  private static final long serialVersionUID = 1110964622197874436L;

  private Integer id;

  private String name;

  private List<String> names;

  @SerializedName("memory")
  private Integer memorySizeInMb;

  @SerializedName("vcpus")
  private Integer virutalCpuCount;

  @SerializedName("disk")
  private Integer diskSize;

  private Region region;

  private Image image;

  @SerializedName("size_slug")
  private String size;

  private boolean locked;

  private DropletStatus status;

  private Networks networks;

  private Kernel kernel;

  @SerializedName("created_at")
  private Date createdDate;

  private List<String> features;

  private Boolean enableBackup;

  private Boolean enableIpv6;

  private Boolean enablePrivateNetworking;

  @SerializedName("backup_ids")
  private List<Integer> backupIds;

  @SerializedName("snapshot_ids")
  private List<Integer> snapshotIds;

  @SerializedName("ssh_keys")
  private List<Key> keys;

  @SerializedName("user_data")
  private String userData;

  @SerializedName("volume_ids")
  private List<String> volumeIds;

  private List<String> tags;

  @SerializedName("monitoring")
  private Boolean installMonitoring;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return true if droplet is active */
  public boolean isActive() {
    return DropletStatus.ACTIVE == status;
  }

  /** @return true if droplet is new, meaning it's booting up */
  public boolean isNew() {
    return DropletStatus.NEW == status;
  }

  /** @return true if droplet is turned off */
  public boolean isOff() {
    return DropletStatus.OFF == status;
  }

  /** @return true if droplet is archived */
  public boolean isArchived() {
    return DropletStatus.ARCHIVE == status;
  }

  /** @return the id */
  public Integer getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(Integer id) {
    this.id = id;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the names */
  public List<String> getNames() {
    return names;
  }

  /** @param names the names to set */
  public void setNames(List<String> names) {
    this.names = names;
  }

  /** @return the memorySizeInMb */
  public Integer getMemorySizeInMb() {
    return memorySizeInMb;
  }

  /** @param memorySizeInMb the memorySizeInMb to set */
  public void setMemorySizeInMb(Integer memorySizeInMb) {
    this.memorySizeInMb = memorySizeInMb;
  }

  /** @return the virutalCpuCount */
  public Integer getVirutalCpuCount() {
    return virutalCpuCount;
  }

  /** @param virutalCpuCount the virutalCpuCount to set */
  public void setVirutalCpuCount(Integer virutalCpuCount) {
    this.virutalCpuCount = virutalCpuCount;
  }

  /** @return the diskSize */
  public Integer getDiskSize() {
    return diskSize;
  }

  /** @param diskSize the diskSize to set */
  public void setDiskSize(Integer diskSize) {
    this.diskSize = diskSize;
  }

  /** @return the region */
  public Region getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(Region region) {
    this.region = region;
  }

  /** @return the image */
  public Image getImage() {
    return image;
  }

  /** @param image the image to set */
  public void setImage(Image image) {
    this.image = image;
  }

  /** @return the size */
  public String getSize() {
    return size;
  }

  /** @param size the size to set */
  public void setSize(String size) {
    this.size = size;
  }

  /** @return the locked */
  public boolean isLocked() {
    return locked;
  }

  /** @param locked the locked to set */
  public void setLocked(boolean locked) {
    this.locked = locked;
  }

  /** @return the status */
  public DropletStatus getStatus() {
    return status;
  }

  /** @param status the status to set */
  public void setStatus(DropletStatus status) {
    this.status = status;
  }

  /** @return the networks */
  public Networks getNetworks() {
    return networks;
  }

  /** @param networks the networks to set */
  public void setNetworks(Networks networks) {
    this.networks = networks;
  }

  /** @return the kernel */
  public Kernel getKernel() {
    return kernel;
  }

  /** @param kernel the kernel to set */
  public void setKernel(Kernel kernel) {
    this.kernel = kernel;
  }

  /** @return the createdDate */
  public Date getCreatedDate() {
    return createdDate;
  }

  /** @param createdDate the createdDate to set */
  public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
  }

  /** @return the features */
  public List<String> getFeatures() {
    return features;
  }

  /** @param features the features to set */
  public void setFeatures(List<String> features) {
    this.features = features;
  }

  /** @return the enableBackup */
  public Boolean getEnableBackup() {
    return enableBackup;
  }

  /** @param enableBackup the enableBackup to set */
  public void setEnableBackup(Boolean enableBackup) {
    this.enableBackup = enableBackup;
  }

  /** @return the enableIpv6 */
  public Boolean getEnableIpv6() {
    return enableIpv6;
  }

  /** @param enableIpv6 the enableIpv6 to set */
  public void setEnableIpv6(Boolean enableIpv6) {
    this.enableIpv6 = enableIpv6;
  }

  /** @return the enablePrivateNetworking */
  public Boolean getEnablePrivateNetworking() {
    return enablePrivateNetworking;
  }

  /** @param enablePrivateNetworking the enablePrivateNetworking to set */
  public void setEnablePrivateNetworking(Boolean enablePrivateNetworking) {
    this.enablePrivateNetworking = enablePrivateNetworking;
  }

  /** @return the backupIds */
  public List<Integer> getBackupIds() {
    return backupIds;
  }

  /** @param backupIds the backupIds to set */
  public void setBackupIds(List<Integer> backupIds) {
    this.backupIds = backupIds;
  }

  /** @return the snapshotIds */
  public List<Integer> getSnapshotIds() {
    return snapshotIds;
  }

  /** @param snapshotIds the snapshotIds to set */
  public void setSnapshotIds(List<Integer> snapshotIds) {
    this.snapshotIds = snapshotIds;
  }

  /** @return the keys */
  public List<Key> getKeys() {
    return keys;
  }

  /** @param keys the keys to set */
  public void setKeys(List<Key> keys) {
    this.keys = keys;
  }

  /** @return the userData */
  public String getUserData() {
    return userData;
  }

  /** @param userData the userData to set */
  public void setUserData(String userData) {
    this.userData = userData;
  }

  /** @return the volumeIds */
  public List<String> getVolumeIds() {
    return volumeIds;
  }

  /** @param volumeIds the volumeIds to set */
  public void setVolumeIds(List<String> volumeIds) {
    this.volumeIds = volumeIds;
  }

  /** @return the tags */
  public List<String> getTags() {
    return tags;
  }

  /** @param tags the tags to set */
  public void setTags(List<String> tags) {
    this.tags = tags;
  }

  /** @return the installMonitoring */
  public Boolean getInstallMonitoring() {
    return installMonitoring;
  }

  /** @param installMonitoring the installMonitoring to set */
  public void setInstallMonitoring(Boolean installMonitoring) {
    this.installMonitoring = installMonitoring;
  }
} public class DropletAction {

  @Expose private ActionType type;

  @Expose private String name;

  @Expose private Integer image;

  @Expose private Integer kernel;

  @Expose private String size;

  @Expose private Boolean disk;

  public DropletAction() {
    // Default Constructor
  }

  public DropletAction(ActionType type) {
    this.type = type;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the type */
  public ActionType getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(ActionType type) {
    this.type = type;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the image */
  public Integer getImage() {
    return image;
  }

  /** @param image the image to set */
  public void setImage(Integer image) {
    this.image = image;
  }

  /** @return the kernel */
  public Integer getKernel() {
    return kernel;
  }

  /** @param kernel the kernel to set */
  public void setKernel(Integer kernel) {
    this.kernel = kernel;
  }

  /** @return the size */
  public String getSize() {
    return size;
  }

  /** @param size the size to set */
  public void setSize(String size) {
    this.size = size;
  }

  /** @return the disk */
  public Boolean getDisk() {
    return disk;
  }

  /** @param disk the size to set */
  public void setDisk(Boolean disk) {
    this.disk = disk;
  }
} public class Droplets extends Base {

  private static final long serialVersionUID = 8034193005189329161L;

  private List<Droplet> droplets;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the droplets */
  public List<Droplet> getDroplets() {
    return droplets;
  }

  /** @param droplets the droplets to set */
  public void setDroplets(List<Droplet> droplets) {
    this.droplets = droplets;
  }
} public class Firewall extends Base {

  private static final long serialVersionUID = -7669528307658280855L;

  private String id;

  private String status;

  @SerializedName("created_at")
  private Date createdDate;

  @SerializedName("pending_changes")
  private List<PendingChanges> pendingChanges;

  @SerializedName("name")
  private String name;

  @Expose
  @SerializedName("inbound_rules")
  private List<InboundRules> inboundRules;

  @Expose
  @SerializedName("outbound_rules")
  private List<OutboundRules> outboundRules;

  @SerializedName("droplet_ids")
  private List<Integer> dropletIds;

  private List<String> tags;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getStatus() {
    return status;
  }

  public void setStatus(String status) {
    this.status = status;
  }

  public Date getCreatedDate() {
    return createdDate;
  }

  public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
  }

  public List<PendingChanges> getPendingChanges() {
    return pendingChanges;
  }

  public void setPendingChanges(List<PendingChanges> pendingChanges) {
    this.pendingChanges = pendingChanges;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public List<InboundRules> getInboundRules() {
    return inboundRules;
  }

  public void setInboundRules(List<InboundRules> inboundRules) {
    this.inboundRules = inboundRules;
  }

  public List<OutboundRules> getOutboundRules() {
    return outboundRules;
  }

  public void setOutboundRules(List<OutboundRules> outboundRules) {
    this.outboundRules = outboundRules;
  }

  public List<Integer> getDropletIds() {
    return dropletIds;
  }

  public void setDropletIds(List<Integer> dropletIds) {
    this.dropletIds = dropletIds;
  }

  public List<String> getTags() {
    return tags;
  }

  public void setTags(List<String> tags) {
    this.tags = tags;
  }
} public class Firewalls extends Base {

  private static final long serialVersionUID = -6358515137857888620L;

  @SerializedName("firewalls")
  private List<Firewall> firewalls;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  public List<Firewall> getFirewalls() {
    return firewalls;
  }

  public void setFirewalls(List<Firewall> firewalls) {
    this.firewalls = firewalls;
  }
} public class FloatingIP extends Base {

  private static final long serialVersionUID = 607751030000684913L;

  private String ip;

  private Region region;

  private Droplet droplet;

  private boolean locked;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the ip */
  public String getIp() {
    return ip;
  }

  /** @param ip the ip to set */
  public void setIp(String ip) {
    this.ip = ip;
  }

  /** @return the region */
  public Region getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(Region region) {
    this.region = region;
  }

  /** @return the droplet */
  public Droplet getDroplet() {
    return droplet;
  }

  /** @param droplet the droplet to set */
  public void setDroplet(Droplet droplet) {
    this.droplet = droplet;
  }

  /** @return the locked */
  public boolean isLocked() {
    return locked;
  }

  /** @param locked the locked to set */
  public void setLocked(boolean locked) {
    this.locked = locked;
  }
} public class FloatingIPAction extends Base {

  private static final long serialVersionUID = -6669790006341807856L;

  @Expose
  @SerializedName("droplet_id")
  private Integer dropletId;

  @Expose private String region;

  @Expose private String type;

  public FloatingIPAction() {
    // default constructor
  }

  public FloatingIPAction(Integer dropletId) {
    this(dropletId, null, null);
  }

  public FloatingIPAction(String region) {
    this(null, region, null);
  }

  public FloatingIPAction(Integer dropletId, String type) {
    this(dropletId, null, type);
  }

  public FloatingIPAction(Integer dropletId, String region, String type) {
    this.dropletId = dropletId;
    this.region = region;
    this.type = type;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the dropletId */
  public Integer getDropletId() {
    return dropletId;
  }

  /** @param dropletId the dropletId to set */
  public void setDropletId(Integer dropletId) {
    this.dropletId = dropletId;
  }

  /** @return the region */
  public String getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(String region) {
    this.region = region;
  }

  /** @return the type */
  public String getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(String type) {
    this.type = type;
  }
} public class FloatingIPs extends Base {

  private static final long serialVersionUID = -5205906300992553434L;

  @SerializedName("floating_ips")
  private List<FloatingIP> floatingIPs;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the floatingIPs */
  public List<FloatingIP> getFloatingIPs() {
    return floatingIPs;
  }

  /** @param floatingIPs the floatingIPs to set */
  public void setFloatingIPs(List<FloatingIP> floatingIPs) {
    this.floatingIPs = floatingIPs;
  }
} public class ForwardingRules extends Base {

  private static final long serialVersionUID = -442836096026412279L;

  @Expose
  @SerializedName("entry_protocol")
  private Protocol entryProtocol;

  @Expose
  @SerializedName("entry_port")
  private Integer entryPort;

  @Expose
  @SerializedName("target_protocol")
  private Protocol targetProtocol;

  @Expose
  @SerializedName("target_port")
  private Integer targetPort;

  @Expose
  @SerializedName("certificate_id")
  private String certificateId;

  @Expose
  @SerializedName("tls_passthrough")
  private boolean tlsPassthrough;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the entry protocol */
  public Protocol getEntryProtocol() {
    return entryProtocol;
  }

  public void setEntryProtocol(Protocol entryProtocol) {
    this.entryProtocol = entryProtocol;
  }

  /** @return the entry port */
  public Integer getEntryPort() {
    return entryPort;
  }

  /** @param entryPort the entry port to set */
  public void setEntryPort(Integer entryPort) {
    this.entryPort = entryPort;
  }

  /** @return the target protocol */
  public Protocol getTargetProtocol() {
    return targetProtocol;
  }

  /** @param targetProtocol the target protocol to set */
  public void setTargetProtocol(Protocol targetProtocol) {
    this.targetProtocol = targetProtocol;
  }

  /** @return the target port */
  public Integer getTargetPort() {
    return targetPort;
  }

  /** @param targetPort the target port to set */
  public void setTargetPort(Integer targetPort) {
    this.targetPort = targetPort;
  }

  /** @return the certificateId */
  public String getCertificateId() {
    return certificateId;
  }

  /** @param certificateId the certificateId to set */
  public void setCertificateId(String certificateId) {
    this.certificateId = certificateId;
  }

  /** @return true if SSL encrypted traffic will be passed through to the backend Droplets */
  public boolean isTlsPassthrough() {
    return tlsPassthrough;
  }

  /** @param tlsPassthrough the tlsPassthrough to set */
  public void setTlsPassthrough(boolean tlsPassthrough) {
    this.tlsPassthrough = tlsPassthrough;
  }
} public class HealthCheck extends Base {

  private static final long serialVersionUID = -442836096026412279L;

  @Expose private Protocol protocol;

  @Expose private Integer port;

  @Expose private String path;

  @Expose
  @SerializedName("check_interval_seconds")
  private Integer checkIntervalInSeconds = 10;

  @Expose
  @SerializedName("response_timeout_seconds")
  private Integer responseTimeoutInSeconds = 5;

  @Expose
  @SerializedName("unhealthy_threshold")
  private Integer unhealthyThreshold = 3;

  @Expose
  @SerializedName("healthy_threshold")
  private Integer healthyThreshold = 5;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the protocol */
  public Protocol getProtocol() {
    return protocol;
  }

  /** @param protocol the protocol to set */
  public void setProtocol(Protocol protocol) {
    this.protocol = protocol;
  }

  /** @return the port */
  public Integer getPort() {
    return port;
  }

  /** @param port the entry port to set */
  public void setPort(Integer port) {
    this.port = port;
  }

  /** @return the path */
  public String getPath() {
    return path;
  }

  /** @param path the path to set */
  public void setPath(String path) {
    this.path = path;
  }

  /**
   * @return the number of times a health check must pass for a backend Droplet to be marked
   *     "healthy" and be re-added to the pool
   */
  public Integer getHealthyThreshold() {
    return healthyThreshold;
  }

  /**
   * @param healthyThreshold the number of times a health check must pass for a backend Droplet to
   *     be marked "healthy" and be re-added to the pool
   */
  public void setHealthyThreshold(Integer healthyThreshold) {
    this.healthyThreshold = healthyThreshold;
  }

  /**
   * @return the number of times a health check must fail for a backend Droplet to be marked
   *     "unhealthy" and be removed from the pool.
   */
  public Integer getUnhealthyThreshold() {
    return unhealthyThreshold;
  }

  /**
   * @param unhealthyThreshold the number of times a health check must fail for a backend Droplet to
   *     be marked "unhealthy" and be removed from the pool.
   */
  public void setUnhealthyThreshold(Integer unhealthyThreshold) {
    this.unhealthyThreshold = unhealthyThreshold;
  }

  /**
   * @return the number of seconds the Load Balancer instance will wait for a response until marking
   *     a health check as failed.
   */
  public Integer getResponseTimeoutInSeconds() {
    return responseTimeoutInSeconds;
  }

  /**
   * @param responseTimeoutInSeconds the number of seconds the Load Balancer instance will wait for
   *     a response until marking a health check as failed.
   */
  public void setResponseTimeoutInSeconds(Integer responseTimeoutInSeconds) {
    this.responseTimeoutInSeconds = responseTimeoutInSeconds;
  }

  /** @return number of seconds between two consecutive health checks */
  public Integer getCheckIntervalInSeconds() {
    return checkIntervalInSeconds;
  }

  /**
   * @param checkIntervalInSeconds the number of seconds between two consecutive health checks to
   *     set
   */
  public void setCheckIntervalInSeconds(Integer checkIntervalInSeconds) {
    this.checkIntervalInSeconds = checkIntervalInSeconds;
  }
} public class Image extends Base {

  private static final long serialVersionUID = 1321111459154107563L;

  private Integer id;

  @Expose private String name;

  @Expose private String distribution;

  private String slug;

  @SerializedName("public")
  private boolean availablePublic;

  private List<String> regions;

  @SerializedName("created_at")
  private Date createdDate;

  @SerializedName("min_disk_size")
  private Integer minDiskSize;

  @SerializedName("size_gigabytes")
  private Double size;

  private ImageType type;

  // #89 - start
  // https://developers.digitalocean.com/documentation/changelog/api-v2/support-for-custom-images-and-image-tagging/
  @Expose private String url;

  @Expose private String region;

  @Expose private String description;

  @Expose private List<String> tags;

  private ImageStatus status;

  @SerializedName("error_message")
  private String errorMessage;
  // #89 - end

  public Image() {
    // Default constructor
  }

  public Image(Integer id) {
    this.id = id;
  }

  public Image(String slug) {
    this.slug = slug;
  }

  public Image(String name, String url, String region) {
    this.name = name;
    this.url = url;
    this.region = region;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return true if image is snapshot */
  public boolean isSnapshot() {
    return ImageType.SNAPSHOT == type;
  }

  /** @return true if image is backup */
  public boolean isBackup() {
    return ImageType.BACKUP == type;
  }

  /** @return the id */
  public Integer getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(Integer id) {
    this.id = id;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /**
   * The name of a custom image's distribution.
   *
   * <p>Currently, the valid values are "Arch Linux", "CentOS", "CoreOS", "Debian", "Fedora",
   * "Fedora Atomic", "FreeBSD", "Gentoo", "openSUSE", "RancherOS", "Ubuntu", and "Unknown". Any
   * other value will be accepted but ignored, and "Unknown" will be used in its place.
   *
   * @return the distribution
   */
  public String getDistribution() {
    return distribution;
  }

  /**
   * The name of a custom image's distribution.
   *
   * <p>Currently, the valid values are "Arch Linux", "CentOS", "CoreOS", "Debian", "Fedora",
   * "Fedora Atomic", "FreeBSD", "Gentoo", "openSUSE", "RancherOS", "Ubuntu", and "Unknown". Any
   * other value will be accepted but ignored, and "Unknown" will be used in its place.
   *
   * @param distribution the distribution to set
   */
  public void setDistribution(String distribution) {
    this.distribution = distribution;
  }

  /** @return the slug */
  public String getSlug() {
    return slug;
  }

  /** @param slug the slug to set */
  public void setSlug(String slug) {
    this.slug = slug;
  }

  /** @return the availablePublic */
  public boolean isAvailablePublic() {
    return availablePublic;
  }

  /** @param availablePublic the availablePublic to set */
  public void setAvailablePublic(boolean availablePublic) {
    this.availablePublic = availablePublic;
  }

  /** @return the regions */
  public List<String> getRegions() {
    return regions;
  }

  /** @param regions the regions to set */
  public void setRegions(List<String> regions) {
    this.regions = regions;
  }

  /** @return the createdDate */
  public Date getCreatedDate() {
    return createdDate;
  }

  /** @param createdDate the createdDate to set */
  public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
  }

  /** @return the type */
  public ImageType getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(ImageType type) {
    this.type = type;
  }

  /** @return the min Disk Size */
  public Integer getMinDiskSize() {
    return minDiskSize;
  }

  /** @param minDiskSize the minDiskSize to set */
  public void setMinDiskSize(Integer minDiskSize) {
    this.minDiskSize = minDiskSize;
  }

  /** @return the size */
  public Double getSize() {
    return size;
  }

  /** @param size the size to set */
  public void setSize(Double size) {
    this.size = size;
  }

  /** @return the url */
  public String getUrl() {
    return url;
  }

  /**
   * A URL from which the custom Linux virtual machine image may be retrieved. The image it points
   * to must be in the raw, qcow2, vhdx, vdi, or vmdk format. It may be compressed using gzip or
   * bzip2 and must be smaller than 100 GB after being decompressed.
   *
   * @param url the url to set
   */
  public void setUrl(String url) {
    this.url = url;
  }

  /** @return the region */
  public String getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(String region) {
    this.region = region;
  }

  /** @return the description */
  public String getDescription() {
    return description;
  }

  /** @param description the description to set */
  public void setDescription(String description) {
    this.description = description;
  }

  /** @return the status */
  public ImageStatus getStatus() {
    return status;
  }

  /** @param status the status to set */
  public void setStatus(ImageStatus status) {
    this.status = status;
  }

  /** @return the tags */
  public List<String> getTags() {
    return tags;
  }

  /** @param tags the tags to set */
  public void setTags(List<String> tags) {
    this.tags = tags;
  }

  /** @return the errorMessage */
  public String getErrorMessage() {
    return errorMessage;
  }

  /** @param errorMessage the errorMessage to set */
  public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
  }
} public class ImageAction {

  @Expose private ActionType type;

  @Expose private String region;

  public ImageAction() {
    this(null, null);
  }

  public ImageAction(ActionType type) {
    this(type, null);
  }

  public ImageAction(ActionType type, String region) {
    this.type = type;
    this.region = region;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the type */
  public ActionType getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(ActionType type) {
    this.type = type;
  }

  /** @return the region */
  public String getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(String region) {
    this.region = region;
  }
} public class Images extends Base {

  private static final long serialVersionUID = 948306822509308453L;

  private List<Image> images;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the images */
  public List<Image> getImages() {
    return images;
  }

  /** @param images the images to set */
  public void setImages(List<Image> images) {
    this.images = images;
  }
} public class Kernels extends Base {

  private static final long serialVersionUID = -272245249038819379L;

  private List<Kernel> kernels;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the kernels */
  public List<Kernel> getKernels() {
    return kernels;
  }

  /** @param kernels the kernels to set */
  public void setKernels(List<Kernel> kernels) {
    this.kernels = kernels;
  }
} public class Key extends Base {

  private static final long serialVersionUID = 3454646433241484585L;

  @Expose private Integer id;

  @Expose private String name;

  @Expose private String fingerprint;

  @Expose
  @SerializedName("public_key")
  private String publicKey;

  public Key() {
    // Default constructor
  }

  public Key(Integer id) {
    this.id = id;
  }

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

  public Key(String name, String publicKey) {
    this.name = name;
    this.publicKey = publicKey;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the id */
  public Integer getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(Integer id) {
    this.id = id;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the fingerprint */
  public String getFingerprint() {
    return fingerprint;
  }

  /** @param fingerprint the fingerprint to set */
  public void setFingerprint(String fingerprint) {
    this.fingerprint = fingerprint;
  }

  /** @return the publicKey */
  public String getPublicKey() {
    return publicKey;
  }

  /** @param publicKey the publicKey to set */
  public void setPublicKey(String publicKey) {
    this.publicKey = publicKey;
  }
} public class Keys extends Base {

  private static final long serialVersionUID = 5842563908358462580L;

  @SerializedName("ssh_keys")
  private List<Key> keys;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the keys */
  public List<Key> getKeys() {
    return keys;
  }

  /** @param keys the keys to set */
  public void setKeys(List<Key> keys) {
    this.keys = keys;
  }
} public class LoadBalancer extends Base {

  private static final long serialVersionUID = -442836096026412279L;

  private String id;

  @Expose private String name;

  private String ip;

  @Expose private LoadBalancingAlgorithm algorithm;

  private Region region;

  private LoadBalancerStatus status;

  @SerializedName("created_at")
  private Date createdDate;

  @SerializedName("forwarding_rules")
  private List<ForwardingRules> forwardingRules;

  @SerializedName("health_check")
  private HealthCheck healthCheck;

  @SerializedName("sticky_sessions")
  private StickySessions stickySessions;

  @SerializedName("redirect_http_to_https")
  private boolean redirectHttpToHttps;

  @SerializedName("droplet_ids")
  private List<String> dropletIds;

  @Expose private String tag;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the ip */
  public String getIp() {
    return ip;
  }

  /** @param ip the ip to set */
  public void setIp(String ip) {
    this.ip = ip;
  }

  /** @return the id */
  public String getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(String id) {
    this.id = id;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the algorithm */
  public LoadBalancingAlgorithm getAlgorithm() {
    return algorithm;
  }

  /** @param algorithm the algorithm to set */
  public void setAlgorithm(LoadBalancingAlgorithm algorithm) {
    this.algorithm = algorithm;
  }

  /** @return the region */
  public Region getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(Region region) {
    this.region = region;
  }

  /** @return the status */
  public LoadBalancerStatus getStatus() {
    return status;
  }

  /** @param status the status to set */
  public void setStatus(LoadBalancerStatus status) {
    this.status = status;
  }

  /** @return the created date */
  public Date getCreatedDate() {
    return createdDate;
  }

  /** @param createdDate the createdDate to set */
  public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
  }

  /** @return the forwarding rules */
  public List<ForwardingRules> getForwardingRules() {
    return forwardingRules;
  }

  /** @param forwardingRules the forwardingRules to set */
  public void setForwardingRules(List<ForwardingRules> forwardingRules) {
    this.forwardingRules = forwardingRules;
  }

  /** @return the healthcheck */
  public HealthCheck getHealthCheck() {
    return healthCheck;
  }

  /** @param healthCheck the healthCheck to set */
  public void setHealthCheck(HealthCheck healthCheck) {
    this.healthCheck = healthCheck;
  }

  /** @return the sticky sessions */
  public StickySessions getStickySessions() {
    return stickySessions;
  }

  /** @param stickySessions the stickySessions to set */
  public void setStickySessions(StickySessions stickySessions) {
    this.stickySessions = stickySessions;
  }

  /**
   * @return true if the HTTP requests to the Load Balancer on port 80 will be redirected to HTTPS
   *     on port 443.
   */
  public boolean isRedirectHttpToHttps() {
    return redirectHttpToHttps;
  }

  /** @param redirectHttpToHttps the redirectHttpToHttps to set */
  public void setRedirectHttpToHttps(boolean redirectHttpToHttps) {
    this.redirectHttpToHttps = redirectHttpToHttps;
  }

  /** @return the list of dropletId */
  public List<String> getDropletIds() {
    return dropletIds;
  }

  /** @param dropletIds the dropletIds to set */
  public void setDropletIds(List<String> dropletIds) {
    this.dropletIds = dropletIds;
  }

  /** @return the tag */
  public String getTag() {
    return tag;
  }

  /** @param tag the tag to set */
  public void setTag(String tag) {
    this.tag = tag;
  }
} public class LoadBalancers extends Base {

  private static final long serialVersionUID = 5440139918030950627L;

  @SerializedName("load_balancers")
  private List<LoadBalancer> loadBalancers;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the droplets */
  public List<LoadBalancer> getLoadBalancers() {
    return loadBalancers;
  }

  /** @param loadBalancers the droplets to set */
  public void setLoadBalancers(List<LoadBalancer> loadBalancers) {
    this.loadBalancers = loadBalancers;
  }
} public class Neighbors extends Base {

  private static final long serialVersionUID = 3735413257818221593L;

  private List<Droplet> neighbors;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the neighbors */
  public List<Droplet> getNeighbors() {
    return neighbors;
  }

  /** @param neighbors the neighbors to set */
  public void setNeighbors(List<Droplet> neighbors) {
    this.neighbors = neighbors;
  }
} public class Project extends Base {

  private static final long serialVersionUID = -594801578631188284L;

  private String id;

  @SerializedName("owner_uuid")
  private String ownerUuid;

  @SerializedName("owner_id")
  private String ownerId;

  @Expose private String name;

  @Expose private String description;

  @Expose private String purpose;

  @Expose private Environment environment;

  @Expose
  @SerializedName("is_default")
  private boolean isDefault;

  @SerializedName("created_at")
  private String createdAt;

  @SerializedName("updated_at")
  private String updatedAt;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getOwnerUuid() {
    return ownerUuid;
  }

  public void setOwnerUuid(String ownerUuid) {
    this.ownerUuid = ownerUuid;
  }

  public String getOwnerId() {
    return ownerId;
  }

  public void setOwnerId(String ownerId) {
    this.ownerId = ownerId;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public String getPurpose() {
    return purpose;
  }

  public void setPurpose(String purpose) {
    this.purpose = purpose;
  }

  public Environment getEnvironment() {
    return environment;
  }

  public void setEnvironment(Environment environment) {
    this.environment = environment;
  }

  public boolean isDefault() {
    return isDefault;
  }

  public void setDefault(boolean aDefault) {
    isDefault = aDefault;
  }

  public String getCreatedAt() {
    return createdAt;
  }

  public void setCreatedAt(String createdAt) {
    this.createdAt = createdAt;
  }

  public String getUpdatedAt() {
    return updatedAt;
  }

  public void setUpdatedAt(String updatedAt) {
    this.updatedAt = updatedAt;
  }
} public class Projects extends Base {

  private static final long serialVersionUID = -7659167641617957056L;

  private List<Project> projects;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the projects */
  public List<Project> getProjects() {
    return projects;
  }

  /** @param projects the projects to set */
  public void setProjects(List<Project> projects) {
    this.projects = projects;
  }
} public class Regions extends Base {

  private static final long serialVersionUID = -6173241777950108168L;

  private List<Region> regions;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the regions */
  public List<Region> getRegions() {
    return regions;
  }

  /** @param regions the regions to set */
  public void setRegions(List<Region> regions) {
    this.regions = regions;
  }
} public class Resource {

  @Expose
  @SerializedName("resource_id")
  private String id;

  @Expose
  @SerializedName("resource_type")
  private ResourceType type;

  public Resource() {
    // Default constructor
  }

  public Resource(String id, ResourceType type) {
    this.id = id;
    this.type = type;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the id */
  public String getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(String id) {
    this.id = id;
  }

  /** @return the type */
  public ResourceType getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(ResourceType type) {
    this.type = type;
  }
} public class Resources {

  @Expose private List<Resource> resources;

  public Resources() {
    // Default Constructor
  }

  public Resources(List<Resource> resources) {
    this.resources = resources;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the resources */
  public List<Resource> getResources() {
    return resources;
  }

  /** @param resources the resources to set */
  public void setResources(List<Resource> resources) {
    this.resources = resources;
  }
} public class Response extends Base {

  private static final long serialVersionUID = 6912100335316878813L;

  @SerializedName("request_status")
  private Boolean isRequestSuccess;

  @SerializedName("status_code")
  private int statusCode;

  /** Default Constructor */
  public Response() {
    // Default Constructor
  }

  /**
   * Parameterized Constructor
   *
   * @param isRequestSuccess whether delete is success or not
   */
  public Response(Boolean isRequestSuccess) {
    this.isRequestSuccess = isRequestSuccess;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the isRequestSuccess */
  public Boolean getIsRequestSuccess() {
    return isRequestSuccess;
  }

  /** @param isRequestSuccess the isRequestSuccess to set */
  public void setIsRequestSuccess(Boolean isRequestSuccess) {
    this.isRequestSuccess = isRequestSuccess;
  }

  /** @return the statusCode */
  public int getStatusCode() {
    return statusCode;
  }

  /** @param statusCode the statusCode to set */
  public void setStatusCode(int statusCode) {
    this.statusCode = statusCode;
  }
} public class Sizes extends Base {

  private static final long serialVersionUID = 8144482770477554617L;

  private List<Size> sizes;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the sizes */
  public List<Size> getSizes() {
    return sizes;
  }

  /** @param sizes the sizes to set */
  public void setSizes(List<Size> sizes) {
    this.sizes = sizes;
  }
} public class Snapshot extends Image {

  private static final long serialVersionUID = 5713559939273842460L;
} public class Snapshots extends Base {

  private static final long serialVersionUID = -8625465848761958108L;

  List<Snapshot> snapshots;

  /** @return the snapshots */
  public List<Snapshot> getSnapshots() {
    return snapshots;
  }

  /** @param snapshots the snapshots to set */
  public void setSnapshots(List<Snapshot> snapshots) {
    this.snapshots = snapshots;
  }
} public class Tag extends Base {

  private static final long serialVersionUID = -5828623466026614221L;

  @Expose private String name;

  private TagResource resources;

  public Tag() {
    // Default constructor
  }

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

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the resources */
  public TagResource getResources() {
    return resources;
  }

  /** @param resources the resources to set */
  public void setResources(TagResource resources) {
    this.resources = resources;
  }
} public class Tags extends Base {

  private static final long serialVersionUID = -5828623466026614221L;

  private List<Tag> tags;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the tags */
  public List<Tag> getTags() {
    return tags;
  }

  /** @param tags the tags to set */
  public void setTags(List<Tag> tags) {
    this.tags = tags;
  }
} public class Volume extends Base {

  private static final long serialVersionUID = 3274091633535612517L;

  private String id;

  private Region region;

  @SerializedName("droplet_ids")
  private Set<Integer> dropletIds;

  private String name;

  private String description;

  @SerializedName("size_gigabytes")
  private Integer size;

  @SerializedName("created_at")
  private Date createdDate;

  @SerializedName("snapshot_id")
  private String snapshotId;

  @SerializedName("filesystem_type")
  private String fileSystemType;

  @SerializedName("filesystem_label")
  private String fileSystemLabel;

  private List<String> tags;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the id */
  public String getId() {
    return id;
  }

  /** @param id the id to set */
  public void setId(String id) {
    this.id = id;
  }

  /** @return the region */
  public Region getRegion() {
    return region;
  }

  /** @param region the region to set */
  public void setRegion(Region region) {
    this.region = region;
  }

  /** @return the dropletIds */
  public Set<Integer> getDropletIds() {
    return dropletIds;
  }

  /** @param dropletIds the dropletIds to set */
  public void setDropletIds(Set<Integer> dropletIds) {
    this.dropletIds = dropletIds;
  }

  /** @return the name */
  public String getName() {
    return name;
  }

  /** @param name the name to set */
  public void setName(String name) {
    this.name = name;
  }

  /** @return the description */
  public String getDescription() {
    return description;
  }

  /** @param description the description to set */
  public void setDescription(String description) {
    this.description = description;
  }

  /** @return the size in Gigabytes */
  public Integer getSize() {
    return size;
  }

  /** @param size the size to set */
  public void setSize(Integer size) {
    this.size = size;
  }

  /** @return the createdDate */
  public Date getCreatedDate() {
    return createdDate;
  }

  /** @param createdDate the createdDate to set */
  public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
  }

  /** @return the snapshotId */
  public String getSnapshotId() {
    return snapshotId;
  }

  /** @param snapshotId the snapshotId to set */
  public void setSnapshotId(String snapshotId) {
    this.snapshotId = snapshotId;
  }

  /** @return the fileSystemType */
  public String getFileSystemType() {
    return fileSystemType;
  }

  /** @param fileSystemType the fileSystemType to set */
  public void setFileSystemType(String fileSystemType) {
    this.fileSystemType = fileSystemType;
  }

  /** @return the fileSystemLabel */
  public String getFileSystemLabel() {
    return fileSystemLabel;
  }

  /** @param fileSystemLabel the fileSystemLabel to set */
  public void setFileSystemLabel(String fileSystemLabel) {
    this.fileSystemLabel = fileSystemLabel;
  }

  /** @return the tags */
  public List<String> getTags() {
    return tags;
  }

  /** @param tags the tags to set */
  public void setTags(List<String> tags) {
    this.tags = tags;
  }
} public class VolumeAction {

  @Expose private ActionType type;

  @Expose
  @SerializedName("droplet_id")
  private Integer dropletId;

  @Expose
  @SerializedName("region")
  private String regionSlug;

  @Expose
  @SerializedName("volume_name")
  private String volumeName;

  @Expose
  @SerializedName("size_gigabytes")
  private Double size;

  /** Constructor */
  public VolumeAction() {
    // Default Constructor
  }

  /**
   * Constructor
   *
   * @param type action type of the volume
   * @param dropletId is to attach/detach volume from droplet
   * @param regionSlug short name of region
   */
  public VolumeAction(ActionType type, Integer dropletId, String regionSlug) {
    this(type, dropletId, regionSlug, null, null);
  }

  /**
   * Constructor
   *
   * @param type action type of the volume
   * @param regionSlug short name of region
   * @param size volume size in GB
   */
  public VolumeAction(ActionType type, String regionSlug, Double size) {
    this(type, null, regionSlug, null, size);
  }

  /**
   * Constructor
   *
   * @param type action type of the volume
   * @param dropletId is to attach/detach volume from droplet
   * @param regionSlug short name of region
   * @param volumeName name of the volume
   * @param size volume size in GB
   */
  public VolumeAction(
      ActionType type, Integer dropletId, String regionSlug, String volumeName, Double size) {
    this.type = type;
    this.dropletId = dropletId;
    this.regionSlug = regionSlug;
    this.volumeName = volumeName;
    this.size = size;
  }

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the type */
  public ActionType getType() {
    return type;
  }

  /** @param type the type to set */
  public void setType(ActionType type) {
    this.type = type;
  }

  /** @return the dropletId */
  public Integer getDropletId() {
    return dropletId;
  }

  /** @param dropletId the dropletId to set */
  public void setDropletId(Integer dropletId) {
    this.dropletId = dropletId;
  }

  /** @return the regionSlug */
  public String getRegionSlug() {
    return regionSlug;
  }

  /** @param regionSlug the regionSlug to set */
  public void setRegionSlug(String regionSlug) {
    this.regionSlug = regionSlug;
  }

  /** @return the volumeName */
  public String getVolumeName() {
    return volumeName;
  }

  /** @param volumeName the volumeName to set */
  public void setVolumeName(String volumeName) {
    this.volumeName = volumeName;
  }

  /** @return the size */
  public Double getSize() {
    return size;
  }

  /** @param size the size to set */
  public void setSize(Double size) {
    this.size = size;
  }
} public class Volumes extends Base {

  private static final long serialVersionUID = 1739002259344347687L;

  private List<Volume> volumes;

  @Override
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }

  /** @return the volumes */
  public List<Volume> getVolumes() {
    return volumes;
  }

  /** @param volumes the volumes to set */
  public void setVolumes(List<Volume> volumes) {
    this.volumes = volumes;
  }
} public class DropletSerializer implements JsonSerializer<Droplet> {

  @Override
  public JsonElement serialize(Droplet droplet, Type paramType, JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();

    jsonObject.addProperty("name", droplet.getName());

    if (null != droplet.getNames() && !droplet.getNames().isEmpty()) {
      JsonArray names = new JsonArray();
      for (String name : droplet.getNames()) {
        names.add(context.serialize(name));
      }
      jsonObject.add("names", names);
    }

    jsonObject.addProperty("region", droplet.getRegion().getSlug());
    jsonObject.addProperty("size", droplet.getSize());

    if (null == droplet.getImage().getId()) {
      jsonObject.addProperty("image", droplet.getImage().getSlug());
    } else {
      jsonObject.addProperty("image", droplet.getImage().getId());
    }

    if (null != droplet.getEnableBackup()) {
      jsonObject.addProperty("backups", droplet.getEnableBackup());
    }

    if (null != droplet.getEnableIpv6()) {
      jsonObject.addProperty("ipv6", droplet.getEnableIpv6());
    }

    if (null != droplet.getEnablePrivateNetworking()) {
      jsonObject.addProperty("private_networking", droplet.getEnablePrivateNetworking());
    }

    if (null != droplet.getKeys() && !droplet.getKeys().isEmpty()) {
      JsonArray sshKeys = new JsonArray();
      for (Key k : droplet.getKeys()) {
        if (null != k.getId()) {
          sshKeys.add(context.serialize(k.getId()));
        }
        if (!StringUtils.isBlank(k.getFingerprint())) {
          sshKeys.add(context.serialize(k.getFingerprint()));
        }
      }
      jsonObject.add("ssh_keys", sshKeys);
    }

    // #19
    if (null != droplet.getUserData()) {
      jsonObject.addProperty("user_data", droplet.getUserData());
    }

    // #56
    if (null != droplet.getVolumeIds() && !droplet.getVolumeIds().isEmpty()) {
      JsonArray volumes = new JsonArray();
      for (String volume : droplet.getVolumeIds()) {
        volumes.add(context.serialize(volume));
      }
      jsonObject.add("volumes", volumes);
    }

    // #56
    if (null != droplet.getTags() && !droplet.getTags().isEmpty()) {
      JsonArray tags = new JsonArray();
      for (String tag : droplet.getTags()) {
        tags.add(context.serialize(tag));
      }
      jsonObject.add("tags", tags);
    }

    // #70
    if (null != droplet.getInstallMonitoring()) {
      jsonObject.addProperty("monitoring", droplet.getInstallMonitoring());
    }

    return jsonObject;
  }
} public class FirewallSerializer implements JsonSerializer<Firewall> {

  @Override
  public JsonElement serialize(
      Firewall firewall, Type paramType, JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();

    jsonObject.addProperty("name", firewall.getName());

    if (null != firewall.getInboundRules() && !firewall.getInboundRules().isEmpty()) {
      JsonArray inboundRules = new JsonArray();
      for (InboundRules inboundRule : firewall.getInboundRules()) {
        inboundRules.add(context.serialize(inboundRule));
      }
      jsonObject.add("inbound_rules", inboundRules);
    }

    if (null != firewall.getOutboundRules() && !firewall.getOutboundRules().isEmpty()) {
      JsonArray outboundRules = new JsonArray();
      for (OutboundRules outboundRule : firewall.getOutboundRules()) {
        outboundRules.add(context.serialize(outboundRule));
      }
      jsonObject.add("outbound_rules", outboundRules);
    }

    if (null != firewall.getDropletIds() && !firewall.getDropletIds().isEmpty()) {
      JsonArray dropletIds = new JsonArray();
      for (Integer dropletId : firewall.getDropletIds()) {
        dropletIds.add(context.serialize(dropletId));
      }
      jsonObject.add("droplet_ids", dropletIds);
    }

    if (null != firewall.getTags() && !firewall.getTags().isEmpty()) {
      JsonArray tags = new JsonArray();
      for (String tag : firewall.getTags()) {
        tags.add(context.serialize(tag));
      }
      jsonObject.add("tags", tags);
    }

    return jsonObject;
  }
} public class LoadBalancerSerializer implements JsonSerializer<LoadBalancer> {

  @Override
  public JsonElement serialize(
      LoadBalancer loadBalancer, Type paramType, JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();

    jsonObject.addProperty("name", loadBalancer.getName());

    jsonObject.addProperty("region", loadBalancer.getRegion().getSlug());

    if (null != loadBalancer.getAlgorithm()) {
      jsonObject.addProperty("algorithm", loadBalancer.getAlgorithm().toString());
    }

    if (null != loadBalancer.getForwardingRules() && !loadBalancer.getForwardingRules().isEmpty()) {
      JsonArray rules = new JsonArray();
      for (ForwardingRules rule : loadBalancer.getForwardingRules()) {
        rules.add(context.serialize(rule));
      }
      jsonObject.add("forwarding_rules", rules);
    }

    if (null != loadBalancer.getHealthCheck()) {
      jsonObject.add("health_check", context.serialize(loadBalancer.getHealthCheck()));
    }

    if (null != loadBalancer.getStickySessions()) {
      jsonObject.add("sticky_sessions", context.serialize(loadBalancer.getStickySessions()));
    }

    if (null != loadBalancer.getDropletIds() && !loadBalancer.getDropletIds().isEmpty()) {
      JsonArray dropletIds = new JsonArray();
      for (String dropletId : loadBalancer.getDropletIds()) {
        dropletIds.add(context.serialize(dropletId));
      }
      jsonObject.add("droplet_ids", dropletIds);
    }
    return jsonObject;
  }
} public class VolumeSerializer implements JsonSerializer<Volume> {

  @Override
  public JsonElement serialize(Volume volume, Type paramType, JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();

    jsonObject.addProperty("id", volume.getId());
    jsonObject.addProperty("name", volume.getName());

    if (StringUtils.isNotBlank(volume.getDescription())) {
      jsonObject.addProperty("description", volume.getDescription());
    }

    if (StringUtils.isNotBlank(volume.getRegion().getSlug())) {
      jsonObject.addProperty("region", volume.getRegion().getSlug());
    }

    if (StringUtils.isNotBlank(volume.getSnapshotId())) {
      jsonObject.addProperty("snapshot_id", volume.getSnapshotId());
    }

    if (null != volume.getSize()) {
      jsonObject.addProperty("size_gigabytes", volume.getSize());
    }

    // #89
    if (StringUtils.isNotBlank(volume.getFileSystemType())) {
      jsonObject.addProperty("filesystem_type", volume.getFileSystemType());
    }

    // #89
    if (StringUtils.isNotBlank(volume.getFileSystemLabel())) {
      jsonObject.addProperty("filesystem_label", volume.getFileSystemLabel());
    }

    // #89
    if (null != volume.getTags() && !volume.getTags().isEmpty()) {
      JsonArray tags = new JsonArray();
      for (String tag : volume.getTags()) {
        tags.add(context.serialize(tag));
      }
      jsonObject.add("tags", tags);
    }

    return jsonObject;
  }
}
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.myjeeva.digitalocean.DigitalOcean;
import com.myjeeva.digitalocean.common.ActionType;
import com.myjeeva.digitalocean.common.ApiAction;
import com.myjeeva.digitalocean.common.Constants;
import com.myjeeva.digitalocean.common.RequestMethod;
import com.myjeeva.digitalocean.exception.DigitalOceanException;
import com.myjeeva.digitalocean.exception.RequestUnsuccessfulException;
import com.myjeeva.digitalocean.http.client.methods.CustomHttpDelete;
import com.myjeeva.digitalocean.pojo.Account;
import com.myjeeva.digitalocean.pojo.Action;
import com.myjeeva.digitalocean.pojo.Actions;
import com.myjeeva.digitalocean.pojo.Backups;
import com.myjeeva.digitalocean.pojo.Certificate;
import com.myjeeva.digitalocean.pojo.Certificates;
import com.myjeeva.digitalocean.pojo.Delete;
import com.myjeeva.digitalocean.pojo.Domain;
import com.myjeeva.digitalocean.pojo.DomainRecord;
import com.myjeeva.digitalocean.pojo.DomainRecords;
import com.myjeeva.digitalocean.pojo.Domains;
import com.myjeeva.digitalocean.pojo.Droplet;
import com.myjeeva.digitalocean.pojo.DropletAction;
import com.myjeeva.digitalocean.pojo.Droplets;
import com.myjeeva.digitalocean.pojo.Firewall;
import com.myjeeva.digitalocean.pojo.Firewalls;
import com.myjeeva.digitalocean.pojo.FloatingIP;
import com.myjeeva.digitalocean.pojo.FloatingIPAction;
import com.myjeeva.digitalocean.pojo.FloatingIPs;
import com.myjeeva.digitalocean.pojo.ForwardingRules;
import com.myjeeva.digitalocean.pojo.HealthCheck;
import com.myjeeva.digitalocean.pojo.Image;
import com.myjeeva.digitalocean.pojo.ImageAction;
import com.myjeeva.digitalocean.pojo.Images;
import com.myjeeva.digitalocean.pojo.Kernels;
import com.myjeeva.digitalocean.pojo.Key;
import com.myjeeva.digitalocean.pojo.Keys;
import com.myjeeva.digitalocean.pojo.LoadBalancer;
import com.myjeeva.digitalocean.pojo.LoadBalancers;
import com.myjeeva.digitalocean.pojo.Neighbors;
import com.myjeeva.digitalocean.pojo.Project;
import com.myjeeva.digitalocean.pojo.Projects;
import com.myjeeva.digitalocean.pojo.Regions;
import com.myjeeva.digitalocean.pojo.Resource;
import com.myjeeva.digitalocean.pojo.Resources;
import com.myjeeva.digitalocean.pojo.Response;
import com.myjeeva.digitalocean.pojo.Sizes;
import com.myjeeva.digitalocean.pojo.Snapshot;
import com.myjeeva.digitalocean.pojo.Snapshots;
import com.myjeeva.digitalocean.pojo.Tag;
import com.myjeeva.digitalocean.pojo.Tags;
import com.myjeeva.digitalocean.pojo.Volume;
import com.myjeeva.digitalocean.pojo.VolumeAction;
import com.myjeeva.digitalocean.pojo.Volumes;
import com.myjeeva.digitalocean.serializer.DropletSerializer;
import com.myjeeva.digitalocean.serializer.FirewallSerializer;
import com.myjeeva.digitalocean.serializer.LoadBalancerSerializer;
import com.myjeeva.digitalocean.serializer.VolumeSerializer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * The MIT License
 *
 * <p>Copyright (c) 2013-2020 Jeevanandam M. (jeeva@myjeeva.com)
 *
 * <p>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:
 *
 * <p>The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * <p>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;


/**
 * DigitalOcean API client wrapper methods Implementation
 *
 * @author Jeevanandam M. (jeeva@myjeeva.com)
 */
public class DigitalOceanClient implements DigitalOcean, Constants {

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

  /** Http client */
  protected CloseableHttpClient httpClient;

  /** OAuth Authorization Token for Accessing DigitalOcean API */
  protected String authToken;

  /** DigitalOcean API version. defaults to v2 from constructor */
  protected String apiVersion;

  /** DigitalOcean API Host is <code>api.digitalocean.com</code> */
  protected String apiHost = "api.digitalocean.com";

  /** Gson Parser instance for deserialize */
  private Gson deserialize;

  /** Gson Parser instance for serialize */
  private Gson serialize;

  /** API Request Header */
  private Header[] requestHeaders;

  /**
   * DigitalOcean Client Constructor
   *
   * @param authToken a {@link String} object
   */
  public DigitalOceanClient(String authToken) {
    this("v2", authToken);
  }

  /**
   * DigitalOcean Client Constructor
   *
   * @param apiVersion a {@link String} object
   * @param authToken a {@link String} object
   */
  public DigitalOceanClient(String apiVersion, String authToken) {
    this(apiVersion, authToken, null);
  }

  /**
   * DigitalOcean Client Constructor
   *
   * @param apiVersion a {@link String} object
   * @param authToken a {@link String} object
   * @param httpClient a {@link CloseableHttpClient} object
   */
  public DigitalOceanClient(String apiVersion, String authToken, CloseableHttpClient httpClient) {

    if (!"v2".equalsIgnoreCase(apiVersion)) {
      throw new IllegalArgumentException("Only API version 2 is supported.");
    }

    this.apiVersion = apiVersion;
    this.authToken = authToken;
    this.httpClient = httpClient;
    initialize();
  }

  /** @return the httpClient */
  public HttpClient getHttpClient() {
    return httpClient;
  }

  /** @param httpClient the httpClient to set */
  public void setHttpClient(CloseableHttpClient httpClient) {
    this.httpClient = httpClient;
  }

  /** @return the authToken */
  public String getAuthToken() {
    return authToken;
  }

  /** @param authToken the authToken to set */
  public void setAuthToken(String authToken) {
    this.authToken = authToken;
  }

  /** @return the apiVersion */
  public String getApiVersion() {
    return apiVersion;
  }

  /** @param apiVersion the apiVersion to set */
  public void setApiVersion(String apiVersion) {
    this.apiVersion = apiVersion;
  }

  // =======================================
  // Droplet access/manipulation methods
  // =======================================

  @Override
  public Droplets getAvailableDroplets(Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validatePageNo(pageNo);

    return (Droplets)
        perform(new ApiRequest(ApiAction.AVAILABLE_DROPLETS, pageNo, perPage)).getData();
  }

  @Override
  public Kernels getDropletKernels(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validateDropletIdAndPageNo(dropletId, pageNo);

    Object[] params = {dropletId};
    return (Kernels)
        perform(new ApiRequest(ApiAction.GET_DROPLETS_KERNELS, params, pageNo, perPage)).getData();
  }

  @Override
  public Snapshots getDropletSnapshots(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validateDropletIdAndPageNo(dropletId, pageNo);

    Object[] params = {dropletId};
    return (Snapshots)
        perform(new ApiRequest(ApiAction.GET_DROPLET_SNAPSHOTS, params, pageNo, perPage)).getData();
  }

  @Override
  public Backups getDropletBackups(Integer dropletId, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validateDropletIdAndPageNo(dropletId, pageNo);

    Object[] params = {dropletId};
    return (Backups)
        perform(new ApiRequest(ApiAction.GET_DROPLET_BACKUPS, params, pageNo, perPage)).getData();
  }

  @Override
  public Droplet getDropletInfo(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validateDropletId(dropletId);

    Object[] params = {dropletId};
    return (Droplet) perform(new ApiRequest(ApiAction.GET_DROPLET_INFO, params)).getData();
  }

  @Override
  public Droplet createDroplet(Droplet droplet)
      throws DigitalOceanException, RequestUnsuccessfulException {
    if (null == droplet
        || StringUtils.isBlank(droplet.getName())
        || null == droplet.getRegion()
        || null == droplet.getSize()
        || (null == droplet.getImage()
            || (null == droplet.getImage().getId() && null == droplet.getImage().getSlug()))) {
      throw new IllegalArgumentException(
          "Missing required parameters [Name, Region Slug, Size Slug, Image Id/Slug] for create droplet.");
    }

    return (Droplet) perform(new ApiRequest(ApiAction.CREATE_DROPLET, droplet)).getData();
  }

  @Override
  public Droplets createDroplets(Droplet droplet)
      throws DigitalOceanException, RequestUnsuccessfulException {
    if (null == droplet
        || (null == droplet.getNames() || droplet.getNames().isEmpty())
        || null == droplet.getRegion()
        || null == droplet.getSize()
        || (null == droplet.getImage()
            || (null == droplet.getImage().getId() && null == droplet.getImage().getSlug()))) {
      throw new IllegalArgumentException(
          "Missing required parameters [Names, Region Slug, Size Slug, Image Id/Slug] for creating multiple droplets.");
    }

    if (StringUtils.isNotBlank(droplet.getName())) {
      throw new IllegalArgumentException(
          "Name parameter is not allowed, while creating multiple droplet instead use 'names' attributes.");
    }

    return (Droplets) perform(new ApiRequest(ApiAction.CREATE_DROPLETS, droplet)).getData();
  }

  @Override
  public Delete deleteDroplet(Integer dropletId)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validateDropletId(dropletId);

    Object[] params = {dropletId};
    return (Delete) perform(new ApiRequest(ApiAction.DELETE_DROPLET, params)).getData();
  }

  @Override
  public Delete deleteDropletByTagName(String tagName)
      throws DigitalOceanException, RequestUnsuccessfulException {
    checkBlankAndThrowError(tagName, "Missing required parameter - tagName.");

    Map<String, String> queryParams = new HashMap<String, String>();
    queryParams.put("tag_name", tagName);
    return (Delete)
        perform(new ApiRequest(ApiAction.DELETE_DROPLET_BY_TAG_NAME, null, queryParams, null))
            .getData();
  }

  @Override
  public Droplets getDropletNeighbors(Integer dropletId, Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validateDropletIdAndPageNo(dropletId, pageNo);

    Object[] params = {dropletId};
    return (Droplets)
        perform(new ApiRequest(ApiAction.GET_DROPLET_NEIGHBORS, params, pageNo, null)).getData();
  }

  @Override
  public Neighbors getAllDropletNeighbors(Integer pageNo)
      throws DigitalOceanException, RequestUnsuccessfulException {
    validatePageNo(pageNo);

    return (Neighbors) perform(new ApiRequest(ApiAction.ALL_DROPLET_NEIGHBORS, pageNo)).getData();
  }

  @Override
  public Droplets getAvailableDropletsByTagName(String tagName, Integer pageNo, Integer perPage)
      throws DigitalOceanException, RequestUnsuccessfulException {
    checkBlankAndThrowError(tagName, "Missing required parameter - tagName.");
    validatePageNo(pageNo);

    Map<String, String> queryParams = new HashMap<String, String>();
    queryParams.put("tag_name", tagName);

    return (Droplets)
        perform(new ApiRequest(ApiAction.AVAILABLE_DROPLETS, pageNo, queryParams, perPage))
            .getData();
  }

  // Droplet action methods

  @Override
  public Action rebootDroplet(Integer dropletId)