org.dasein.cloud.nimbula.NimbulaMethod.java Source code

Java tutorial

Introduction

Here is the source code for org.dasein.cloud.nimbula.NimbulaMethod.java

Source

/**
 * Copyright (C) 2009-2012 enStratus Networks Inc
 *
 * ====================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ====================================================================
 */

package org.dasein.cloud.nimbula;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.ProviderContext;
import org.json.JSONException;
import org.json.JSONObject;

public class NimbulaMethod {
    static private final Logger logger = NimbulaDirector.getLogger(NimbulaMethod.class);
    static private final Logger wire = NimbulaDirector.getWireLogger(NimbulaMethod.class);

    private String authCookie = null;
    private NimbulaDirector cloud = null;
    private String response = null;
    private String url = null;

    public NimbulaMethod(@Nonnull NimbulaDirector cloud, @Nonnull String resource) throws CloudException {
        super();
        ProviderContext ctx = cloud.getContext();

        if (ctx == null) {
            throw new CloudException("No context was set for this request");
        }

        Properties properties = ctx.getCustomProperties();
        String ignoreCertSignature = null;

        if (properties != null) {
            ignoreCertSignature = properties.getProperty("ignoreCertSignature", "false");
        }

        if (ignoreCertSignature != null && ignoreCertSignature.equalsIgnoreCase("true")) {
            /*
            ProtocolSocketFactory sf = new EasySsl();
            Protocol easyhttps = new Protocol("https", sf, 443 );
            Protocol.registerProtocol( "https", easyhttps );
            */
        }
        this.cloud = cloud;
        url = cloud.getURL(resource);
        if (properties != null) {
            authCookie = properties.getProperty("nimbulaAuthCookie");
        }
        if (authCookie != null && authCookie.trim().length() < 1) {
            authCookie = null;
        }
    }

    private @Nonnull HttpClient getClient(@Nonnull ProviderContext ctx, boolean ssl) {
        HttpParams params = new BasicHttpParams();

        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        //noinspection deprecation
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
        HttpProtocolParams.setUserAgent(params, "Dasein Cloud");

        Properties p = ctx.getCustomProperties();

        if (p != null) {
            String proxyHost = p.getProperty("proxyHost");
            String proxyPort = p.getProperty("proxyPort");

            if (proxyHost != null) {
                int port = 0;

                if (proxyPort != null && proxyPort.length() > 0) {
                    port = Integer.parseInt(proxyPort);
                }
                params.setParameter(ConnRoutePNames.DEFAULT_PROXY,
                        new HttpHost(proxyHost, port, ssl ? "https" : "http"));
            }
        }
        return new DefaultHttpClient(params);
    }

    private void authenticate() throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".authenticate()");
        }
        try {
            if (authCookie != null) {
                return;
            }
            String uri = cloud.getURL("authenticate") + "/";

            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [POST (" + (new Date()) + ")] -> " + uri
                        + " >--------------------------------------------------------------------------------------");
            }
            try {
                ProviderContext ctx = cloud.getContext();

                if (ctx == null) {
                    throw new CloudException("Unable to authenticate without a context");
                }
                HttpClient client = getClient(ctx, uri.startsWith("https"));
                HttpPost post = new HttpPost(uri);
                HashMap<String, Object> request = new HashMap<String, Object>();

                try {
                    request.put("user",
                            "/" + ctx.getAccountNumber() + "/" + new String(ctx.getAccessPublic(), "utf-8"));
                    request.put("password", new String(ctx.getAccessPrivate(), "utf-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new InternalException(e);
                }
                post.addHeader("Accept", "application/nimbula-v2+json");

                try {
                    //noinspection deprecation
                    post.setEntity(new StringEntity((new JSONObject(request)).toString(),
                            "application/nimbula-v2+json", "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new InternalException(e);
                }
                if (wire.isDebugEnabled()) {
                    wire.debug(post.getRequestLine().toString());
                    for (Header header : post.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");

                    try {
                        wire.debug(EntityUtils.toString(post.getEntity()));
                    } catch (IOException ignore) {
                    }

                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(post);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);

                if (code != HttpServletResponse.SC_NO_CONTENT) {
                    HttpEntity entity = response.getEntity();
                    String data = "";

                    if (entity != null) {
                        try {
                            data = EntityUtils.toString(entity);
                        } catch (IOException e) {
                            throw new CloudException(e);
                        }
                    }
                    if (wire.isDebugEnabled()) {
                        wire.debug(data);
                        wire.debug("");
                    }
                }
                checkResponse(response, code);
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [POST (" + (new Date()) + ")] -> " + uri
                            + " <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".authenticate()");
            }
        }
    }

    private void checkResponse(@Nonnull HttpResponse response, @Nonnegative int code)
            throws CloudException, InternalException {
        checkResponse(response, code, null);
    }

    private @Nonnull String getErrorMessage(@Nullable String body, @Nonnull String defaultMessage) {
        if (body != null) {
            try {
                JSONObject ob = new JSONObject(body);
                String msg = ob.getString("message");

                if (ob.has("reference")) {
                    String ref = ob.getString("reference");

                    if (ref != null) {
                        msg = msg + " [reference=" + ref + "]";
                    }
                }
                return msg;
            } catch (Throwable ignore) {
                // ignore
            }
        }
        return defaultMessage;
    }

    private void checkResponse(@Nonnull HttpResponse response, @Nonnegative int code, @Nullable String responseBody)
            throws CloudException, InternalException {
        ProviderContext ctx = cloud.getContext();

        if (ctx == null) {
            throw new CloudException("No context is set for this request");
        }
        Header[] headers = response.getHeaders("Set-Cookie");

        if (headers != null) {
            for (Header header : headers) {
                if (header.getValue().startsWith("nimbula=")) {
                    authCookie = header.getValue();

                    Properties props = ctx.getCustomProperties();

                    if (props == null) {
                        props = new Properties();
                        ctx.setCustomProperties(props);
                    }
                    props.setProperty("nimbulaAuthCookie", authCookie);
                }
            }
        }
        String message;

        switch (code) {
        case 401:
            message = getErrorMessage(responseBody, "You must authenticate before making this call");
            throw new InternalException(code + ": " + message);
        case 403:
            message = getErrorMessage(responseBody, "You do not have access to the requested resource");
            throw new CloudException(code + ": " + message);
        case 404:
            return;
        case 405:
            message = getErrorMessage(responseBody, "Invalid HTTP method");
            throw new InternalException(code + ": " + message);
        case 406:
            message = getErrorMessage(responseBody, "Invalid request for resource");
            throw new InternalException(code + ": " + message);
        case 409:
            message = getErrorMessage(responseBody, "A conflict exists with the resource you were accessing");
            throw new CloudException(code + ": " + message);
        case 410:
            message = getErrorMessage(responseBody, "The resource you are referencing no longer exists");
            throw new CloudException(code + ": " + message);
        case 415:
            message = getErrorMessage(responseBody, "Request is not JSON");
            throw new InternalException(code + ": " + message);
        default:
            if (code >= 500) {
                message = getErrorMessage(responseBody, "Unknown error");
                throw new CloudException(code + ": " + message);
            }
        }
    }

    public @Nonnegative int delete(@Nonnull String target) throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".delete(" + target + ")");
        }
        try {
            authenticate();
            String service = getUrl(url, target);

            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [DELETE (" + (new Date()) + ")] -> " + service
                        + " >--------------------------------------------------------------------------------------");
            }
            try {
                ProviderContext ctx = cloud.getContext();

                if (ctx == null) {
                    throw new CloudException("No context was set for this request");
                }
                HttpClient client = getClient(ctx, service.startsWith("https"));
                HttpDelete delete = new HttpDelete(service);

                delete.addHeader("Accept", "application/nimbula-v2+json");
                delete.setHeader("Cookie", authCookie);
                if (wire.isDebugEnabled()) {
                    wire.debug(delete.getRequestLine().toString());
                    for (Header header : delete.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(delete);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);
                checkResponse(response, code);
                return code;
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [DELETE (" + (new Date()) + ")] -> " + service
                            + " <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".delete()");
            }
        }
    }

    public @Nonnegative int get(@Nonnull String target) throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".get(" + target + ")");
        }
        try {
            authenticate();

            if (!target.startsWith("/")) {
                target = getUrl(url, target);
            } else {
                target = url + target;
            }

            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [GET (" + (new Date()) + ")] -> " + target
                        + " >--------------------------------------------------------------------------------------");
            }
            try {
                ProviderContext ctx = cloud.getContext();

                if (ctx == null) {
                    throw new CloudException("No context was set for this request");
                }
                HttpClient client = getClient(ctx, target.startsWith("https"));
                HttpGet get = new HttpGet(target);

                get.addHeader("Accept", "application/nimbula-v2+json");
                get.setHeader("Cookie", authCookie);

                if (wire.isDebugEnabled()) {
                    wire.debug(get.getRequestLine().toString());
                    for (Header header : get.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(get);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);

                if (code == 401) {
                    return code;
                }
                if (code != HttpServletResponse.SC_NO_CONTENT) {
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        try {
                            this.response = EntityUtils.toString(entity);

                            if (wire.isDebugEnabled()) {
                                wire.debug(this.response);
                                wire.debug("");
                            }
                        } catch (IOException e) {
                            throw new CloudException(e);
                        }
                    }
                }
                checkResponse(response, code);
                return code;
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [GET (" + (new Date()) + ")] -> " + target
                            + " <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".get()");
            }
        }
    }

    public @Nonnull JSONObject getResponseBody() throws JSONException {
        return new JSONObject(response);
    }

    private @Nonnull String getUrl(@Nonnull String endpoint, @Nullable String id)
            throws CloudException, InternalException {
        ProviderContext ctx = cloud.getContext();

        if (ctx == null) {
            throw new CloudException("No context is set for this request");
        }
        try {
            String user = new String(ctx.getAccessPublic(), "utf-8");
            String account = ctx.getAccountNumber();

            if (!endpoint.endsWith("/")) {
                if (id != null && id.startsWith("/")) {
                    return endpoint + id;
                } else if (id != null) {
                    return endpoint + "/" + account + "/" + user + "/" + id;
                } else {
                    return endpoint + "/" + account + "/" + user;
                }
            } else if (id != null && id.startsWith("/")) {
                if (id.equals("/")) {
                    return endpoint;
                } else {
                    return endpoint + id.substring(1);
                }
            } else if (id != null) {
                return endpoint + id;
            } else {
                return endpoint + account + "/" + user;
            }
        } catch (UnsupportedEncodingException e) {
            throw new InternalException(e);
        }
    }

    public @Nonnegative int list() throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".list()");
        }
        try {
            ProviderContext ctx = cloud.getContext();

            if (ctx == null) {
                throw new CloudException("No context was set for this request");
            }
            authenticate();

            String target;

            if (url.endsWith("info")) {
                target = url + "/";
            } else {
                target = url + "/" + ctx.getAccountNumber() + "/";
            }
            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [GET (" + (new Date()) + ")] -> " + target
                        + " >--------------------------------------------------------------------------------------");
            }
            try {
                HttpClient client = getClient(ctx, target.startsWith("https"));
                HttpGet get = new HttpGet(target);

                get.addHeader("Accept", "application/nimbula-v2+json");
                get.setHeader("Cookie", authCookie);

                if (wire.isDebugEnabled()) {
                    wire.debug(get.getRequestLine().toString());
                    for (Header header : get.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(get);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);

                if (code != HttpServletResponse.SC_NO_CONTENT) {
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        try {
                            this.response = EntityUtils.toString(entity);
                            if (wire.isDebugEnabled()) {
                                wire.debug(this.response);
                                wire.debug("");
                            }
                        } catch (IOException e) {
                            throw new CloudException(e);
                        }
                    }
                }
                checkResponse(response, code);
                return code;
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [GET (" + (new Date()) + ")] -> " + target
                            + " <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".list()");
            }
        }
    }

    @SuppressWarnings("unused")
    public @Nonnegative int discover() throws CloudException, InternalException {
        return discover(null);
    }

    public @Nonnegative int discover(@Nullable String userId) throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".discover(" + userId + ")");
        }
        try {
            authenticate();

            ProviderContext ctx = cloud.getContext();

            if (ctx == null) {
                throw new CloudException("No context was set for this request");
            }

            String target = "/" + ctx.getAccountNumber() + "/";

            if (userId != null) {
                target = target + userId + "/";
            }
            target = url + target;

            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [GET (" + (new Date()) + ")] -> " + target
                        + " >--------------------------------------------------------------------------------------");
            }
            try {
                HttpClient client = getClient(ctx, target.startsWith("https"));
                HttpGet get = new HttpGet(target);

                get.addHeader("Accept", "application/nimbula-v2+directory+json");
                get.setHeader("Cookie", authCookie);

                if (wire.isDebugEnabled()) {
                    wire.debug(get.getRequestLine().toString());
                    for (Header header : get.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(get);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);

                if (code != HttpServletResponse.SC_NO_CONTENT) {
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        try {
                            this.response = EntityUtils.toString(entity);
                            if (wire.isDebugEnabled()) {
                                wire.debug(this.response);
                                wire.debug("");
                            }
                        } catch (IOException e) {
                            throw new CloudException(e);
                        }
                    }
                }
                checkResponse(response, code);
                return code;
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [GET (" + (new Date()) + ")] -> " + target
                            + " <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".discover()");
            }
        }
    }

    public @Nonnegative int post(@Nonnull Map<String, Object> state) throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".post(" + state + ")");
        }
        try {
            authenticate();
            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [POST (" + (new Date()) + ")] -> " + url
                        + "/ >--------------------------------------------------------------------------------------");
            }
            try {
                ProviderContext ctx = cloud.getContext();

                if (ctx == null) {
                    throw new CloudException("No context was set for this request");
                }
                HttpClient client = getClient(ctx, url.startsWith("https"));
                HttpPost post = new HttpPost(url + "/");

                post.setHeader("Cookie", authCookie);
                post.addHeader("Accept", "application/nimbula-v2+json");
                try {
                    //noinspection deprecation
                    post.setEntity(new StringEntity((new JSONObject(state)).toString(),
                            "application/nimbula-v2+json", "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new InternalException(e);
                }

                if (wire.isDebugEnabled()) {
                    wire.debug(post.getRequestLine().toString());
                    for (Header header : post.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");

                    try {
                        wire.debug(EntityUtils.toString(post.getEntity()));
                    } catch (IOException ignore) {
                    }

                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(post);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);

                if (code != HttpServletResponse.SC_NO_CONTENT) {
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        try {
                            this.response = EntityUtils.toString(entity);
                        } catch (IOException e) {
                            throw new CloudException(e);
                        }
                        if (wire.isDebugEnabled()) {
                            wire.debug(this.response);
                            wire.debug("");
                        }
                    }
                    checkResponse(response, code, this.response);
                } else {
                    checkResponse(response, code);
                }
                return code;
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [POST (" + (new Date()) + ")] -> " + url
                            + "/ <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".post()");
            }
        }
    }

    @SuppressWarnings("unused")
    public @Nonnegative int put(@Nonnull String targetId, @Nonnull Map<String, Object> state)
            throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER - " + NimbulaMethod.class.getName() + ".put(" + targetId + "," + state + ")");
        }
        try {
            authenticate();
            String target = getUrl(url, targetId);

            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug(">>> [PUT (" + (new Date()) + ")] -> " + target
                        + " >--------------------------------------------------------------------------------------");
            }
            try {
                ProviderContext ctx = cloud.getContext();

                if (ctx == null) {
                    throw new CloudException("No context was set for this request");
                }
                HttpClient client = getClient(ctx, target.startsWith("https"));
                HttpPut put = new HttpPut(target);

                put.addHeader("Content-Type", "application/json");
                put.setHeader("Cookie", authCookie);
                try {
                    //noinspection deprecation
                    put.setEntity(
                            new StringEntity((new JSONObject(state)).toString(), "application/json", "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new InternalException(e);
                }

                if (wire.isDebugEnabled()) {
                    wire.debug(put.getRequestLine().toString());
                    for (Header header : put.getAllHeaders()) {
                        wire.debug(header.getName() + ": " + header.getValue());
                    }
                    wire.debug("");

                    try {
                        wire.debug(EntityUtils.toString(put.getEntity()));
                    } catch (IOException ignore) {
                    }

                    wire.debug("");
                }
                HttpResponse response;

                try {
                    response = client.execute(put);
                    if (wire.isDebugEnabled()) {
                        wire.debug(response.getStatusLine().toString());
                        for (Header header : response.getAllHeaders()) {
                            wire.debug(header.getName() + ": " + header.getValue());
                        }
                        wire.debug("");
                    }
                } catch (IOException e) {
                    logger.error("I/O error from server communications: " + e.getMessage());
                    e.printStackTrace();
                    throw new InternalException(e);
                }
                int code = response.getStatusLine().getStatusCode();

                logger.debug("HTTP STATUS: " + code);

                if (code != HttpServletResponse.SC_NO_CONTENT) {
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        try {
                            this.response = EntityUtils.toString(entity);
                        } catch (IOException e) {
                            throw new CloudException(e);
                        }
                        if (wire.isDebugEnabled()) {
                            wire.debug(this.response);
                            wire.debug("");
                        }
                    }
                    checkResponse(response, code, this.response);
                } else {
                    checkResponse(response, code);
                }
                return code;
            } finally {
                if (wire.isDebugEnabled()) {
                    wire.debug("<<< [PUT (" + (new Date()) + ")] -> " + url
                            + "/ <--------------------------------------------------------------------------------------");
                    wire.debug("");
                }
            }
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("exit - " + NimbulaMethod.class.getName() + ".put()");
            }
        }
    }
}