org.dasein.cloud.ibm.sce.SCEMethod.java Source code

Java tutorial

Introduction

Here is the source code for org.dasein.cloud.ibm.sce.SCEMethod.java

Source

/**
 * Copyright (C) 2012-2013 Dell, Inc.
 * See annotations for authorship information
 *
 * ====================================================================
 * 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.ibm.sce;

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.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnRoutePNames;
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.CloudErrorType;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.ProviderContext;
import org.dasein.cloud.util.APITrace;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

/**
 * IBM SmartCloud REST API interaction management. Encapsulates the authentication and wire protocol for talking to
 * IBM SmartCloud.
 * <p>Created by George Reese: 7/16/12 7:38 PM</p>
 * @author George Reese
 * @version 2012.04 initial version
 * @since 2012.04
 */
public class SCEMethod {
    private String endpoint;
    private SCE provider;

    public SCEMethod(SCE cloud) throws InternalException {
        provider = cloud;
        ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new SCEConfigException("No context was provided for this request");
        }
        endpoint = ctx.getEndpoint();
        if (endpoint == null) {
            throw new SCEConfigException("No endpoint was provided for this request");
        }
        if (!endpoint.endsWith("/")) {
            endpoint = endpoint + "/";
        }
    }

    public void delete(@Nonnull String resource) throws CloudException, InternalException {
        Logger std = SCE.getLogger(SCEMethod.class, "std");
        Logger wire = SCE.getLogger(SCEMethod.class, "wire");

        if (std.isTraceEnabled()) {
            std.trace("enter - " + SCEMethod.class.getName() + ".post(" + resource + ")");
        }
        if (wire.isDebugEnabled()) {
            wire.debug("POST --------------------------------------------------------> " + endpoint + resource);
            wire.debug("");
        }
        try {
            HttpClient client = getClient();
            HttpDelete method = new HttpDelete(endpoint + resource);

            method.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            if (wire.isDebugEnabled()) {
                wire.debug(method.getRequestLine().toString());
                for (Header header : method.getAllHeaders()) {
                    wire.debug(header.getName() + ": " + header.getValue());
                }
                wire.debug("");
            }
            HttpResponse response;
            StatusLine status;

            try {
                APITrace.trace(provider, resource);
                response = client.execute(method);
                status = response.getStatusLine();
            } catch (IOException e) {
                std.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage());
                if (std.isTraceEnabled()) {
                    e.printStackTrace();
                }
                throw new CloudException(e);
            }
            if (std.isDebugEnabled()) {
                std.debug("post(): HTTP Status " + status);
            }
            Header[] headers = response.getAllHeaders();

            if (wire.isDebugEnabled()) {
                wire.debug(status.toString());
                for (Header h : headers) {
                    if (h.getValue() != null) {
                        wire.debug(h.getName() + ": " + h.getValue().trim());
                    } else {
                        wire.debug(h.getName() + ":");
                    }
                }
                wire.debug("");
            }
            if (status.getStatusCode() != HttpServletResponse.SC_OK
                    && status.getStatusCode() != HttpServletResponse.SC_CREATED
                    && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED) {
                std.error("post(): Expected OK for GET request, got " + status.getStatusCode());

                HttpEntity entity = response.getEntity();

                if (entity == null) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            "An error was returned without explanation");
                }
                String body;

                try {
                    body = EntityUtils.toString(entity);
                } catch (IOException e) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            e.getMessage());
                }
                if (wire.isDebugEnabled()) {
                    wire.debug(body);
                }
                wire.debug("");
                throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                        body);
            }
        } finally {
            if (std.isTraceEnabled()) {
                std.trace("exit - " + SCEMethod.class.getName() + ".post()");
            }
            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug("POST --------------------------------------------------------> " + endpoint + resource);
            }
        }
    }

    public @Nullable Document getAsXML(@Nonnull String resource) throws CloudException, InternalException {
        try {
            return getAsXML(new URI(endpoint + resource), resource);
        } catch (URISyntaxException e) {
            throw new InternalException(
                    "Endpoint misconfiguration (" + endpoint + resource + "): " + e.getMessage());
        }
    }

    public @Nullable Document getAsXML(@Nonnull URI uri, @Nonnull String resource)
            throws CloudException, InternalException {
        Logger std = SCE.getLogger(SCEMethod.class, "std");
        Logger wire = SCE.getLogger(SCEMethod.class, "wire");

        if (std.isTraceEnabled()) {
            std.trace("enter - " + SCEMethod.class.getName() + ".get(" + uri + ")");
        }
        if (wire.isDebugEnabled()) {
            wire.debug("--------------------------------------------------------> " + uri.toASCIIString());
            wire.debug("");
        }
        try {
            HttpClient client = getClient();
            HttpUriRequest get = new HttpGet(uri);

            get.addHeader("Accept", "text/xml");
            if (wire.isDebugEnabled()) {
                wire.debug(get.getRequestLine().toString());
                for (Header header : get.getAllHeaders()) {
                    wire.debug(header.getName() + ": " + header.getValue());
                }
                wire.debug("");
            }
            HttpResponse response;
            StatusLine status;

            try {
                APITrace.trace(provider, resource);
                response = client.execute(get);
                status = response.getStatusLine();
            } catch (IOException e) {
                std.error("get(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage());
                if (std.isTraceEnabled()) {
                    e.printStackTrace();
                }
                throw new CloudException(e);
            }
            if (std.isDebugEnabled()) {
                std.debug("get(): HTTP Status " + status);
            }
            Header[] headers = response.getAllHeaders();

            if (wire.isDebugEnabled()) {
                wire.debug(status.toString());
                for (Header h : headers) {
                    if (h.getValue() != null) {
                        wire.debug(h.getName() + ": " + h.getValue().trim());
                    } else {
                        wire.debug(h.getName() + ":");
                    }
                }
                wire.debug("");
            }
            if (status.getStatusCode() == HttpServletResponse.SC_NOT_FOUND) {
                return null;
            }
            if (status.getStatusCode() != HttpServletResponse.SC_OK
                    && status.getStatusCode() != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION) {
                std.error("get(): Expected OK for GET request, got " + status.getStatusCode());

                HttpEntity entity = response.getEntity();
                String body;

                if (entity == null) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            "An error was returned without explanation");
                }
                try {
                    body = EntityUtils.toString(entity);
                } catch (IOException e) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            e.getMessage());
                }
                if (wire.isDebugEnabled()) {
                    wire.debug(body);
                }
                wire.debug("");
                throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                        body);
            } else {
                HttpEntity entity = response.getEntity();

                if (entity == null) {
                    return null;
                }
                InputStream input;

                try {
                    input = entity.getContent();
                } catch (IOException e) {
                    std.error("get(): Failed to read response error due to a cloud I/O error: " + e.getMessage());
                    if (std.isTraceEnabled()) {
                        e.printStackTrace();
                    }
                    throw new CloudException(e);
                }
                return parseResponse(input, true);
            }
        } finally {
            if (std.isTraceEnabled()) {
                std.trace("exit - " + SCEMethod.class.getName() + ".getStream()");
            }
            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug("--------------------------------------------------------> " + uri.toASCIIString());
            }
        }
    }

    protected @Nonnull HttpClient getClient() throws InternalException {
        ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new SCEConfigException("No context was defined for this request");
        }
        String endpoint = ctx.getEndpoint();

        if (endpoint == null) {
            throw new SCEConfigException("No cloud endpoint was defined");
        }
        boolean ssl = endpoint.startsWith("https");
        int targetPort;
        URI uri;

        try {
            uri = new URI(endpoint);
            targetPort = uri.getPort();
            if (targetPort < 1) {
                targetPort = (ssl ? 443 : 80);
            }
        } catch (URISyntaxException e) {
            throw new SCEConfigException(e);
        }
        HttpHost targetHost = new HttpHost(uri.getHost(), targetPort, uri.getScheme());
        HttpParams params = new BasicHttpParams();

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

        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"));
            }
        }
        DefaultHttpClient client = new DefaultHttpClient(params);

        try {
            String userName = new String(ctx.getAccessPublic(), "utf-8");
            String password = new String(ctx.getAccessPrivate(), "utf-8");

            client.getCredentialsProvider().setCredentials(
                    new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                    new UsernamePasswordCredentials(userName, password));
        } catch (UnsupportedEncodingException e) {
            throw new InternalException(e);
        }
        return client;
    }

    public @Nonnull Document parseResponse(@Nonnull String responseBody, boolean withWireLogging)
            throws CloudException, InternalException {
        Logger wire = (withWireLogging ? SCE.getLogger(SCEMethod.class, "wire") : null);

        try {
            if (wire != null && wire.isDebugEnabled()) {
                String[] lines = responseBody.split("\n");

                if (lines.length < 1) {
                    lines = new String[] { responseBody };
                }
                for (String l : lines) {
                    wire.debug(l);
                }
                wire.debug("");
            }
            ByteArrayInputStream bas = new ByteArrayInputStream(responseBody.getBytes());

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = factory.newDocumentBuilder();
            Document doc = parser.parse(bas);

            bas.close();
            return doc;
        } catch (IOException e) {
            throw new CloudException(e);
        } catch (ParserConfigurationException e) {
            throw new CloudException(e);
        } catch (SAXException e) {
            throw new CloudException(e);
        }
    }

    public @Nonnull Document parseResponse(@Nonnull InputStream responseBodyAsStream, boolean withWireLogging)
            throws CloudException, InternalException {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(responseBodyAsStream));
            StringBuilder sb = new StringBuilder();
            String line;

            while ((line = in.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
            in.close();

            return parseResponse(sb.toString(), withWireLogging);
        } catch (IOException e) {
            throw new CloudException(e);
        }
    }

    public @Nullable String post(@Nonnull String resource, @Nonnull List<NameValuePair> parameters)
            throws CloudException, InternalException {
        Logger std = SCE.getLogger(SCEMethod.class, "std");
        Logger wire = SCE.getLogger(SCEMethod.class, "wire");

        if (std.isTraceEnabled()) {
            std.trace("enter - " + SCEMethod.class.getName() + ".post(" + resource + ")");
        }
        if (wire.isDebugEnabled()) {
            wire.debug("POST --------------------------------------------------------> " + endpoint + resource);
            wire.debug("");
        }
        try {
            HttpClient client = getClient();
            HttpPost post = new HttpPost(endpoint + resource);

            post.addHeader("Content-Type", "application/x-www-form-urlencoded");
            post.addHeader("Accept", "text/xml");

            if (wire.isDebugEnabled()) {
                wire.debug(post.getRequestLine().toString());
                for (Header header : post.getAllHeaders()) {
                    wire.debug(header.getName() + ": " + header.getValue());
                }
                wire.debug("");
                if (parameters != null) {
                    Iterator<NameValuePair> it = parameters.iterator();
                    StringBuilder str = new StringBuilder();

                    while (it.hasNext()) {
                        NameValuePair p = it.next();

                        str.append(p.getName()).append("=").append(p.getValue());
                        if (it.hasNext()) {
                            str.append("&");
                        }
                    }
                    wire.debug(str.toString());
                    wire.debug("");
                }
            }
            if (parameters != null) {
                try {
                    post.setEntity(new UrlEncodedFormEntity(parameters, "utf-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new InternalException(e);
                }
            }
            HttpResponse response;
            StatusLine status;

            try {
                APITrace.trace(provider, resource);
                response = client.execute(post);
                status = response.getStatusLine();
            } catch (IOException e) {
                std.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage());
                if (std.isTraceEnabled()) {
                    e.printStackTrace();
                }
                throw new CloudException(e);
            }
            if (std.isDebugEnabled()) {
                std.debug("post(): HTTP Status " + status);
            }
            Header[] headers = response.getAllHeaders();

            if (wire.isDebugEnabled()) {
                wire.debug(status.toString());
                for (Header h : headers) {
                    if (h.getValue() != null) {
                        wire.debug(h.getName() + ": " + h.getValue().trim());
                    } else {
                        wire.debug(h.getName() + ":");
                    }
                }
                wire.debug("");
            }
            if (status.getStatusCode() != HttpServletResponse.SC_OK
                    && status.getStatusCode() != HttpServletResponse.SC_CREATED
                    && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED) {
                std.error("post(): Expected OK for GET request, got " + status.getStatusCode());

                HttpEntity entity = response.getEntity();
                String body;

                if (entity == null) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            "An error was returned without explanation");
                }
                try {
                    body = EntityUtils.toString(entity);
                } catch (IOException e) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            e.getMessage());
                }
                if (wire.isDebugEnabled()) {
                    wire.debug(body);
                }
                wire.debug("");
                throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                        body);
            } else if (status.getStatusCode() == HttpServletResponse.SC_NO_CONTENT) {
                return null;
            } else {
                HttpEntity entity = response.getEntity();

                if (entity == null) {
                    return null;
                }
                try {
                    return EntityUtils.toString(entity);
                } catch (IOException e) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            e.getMessage());
                }
            }
        } finally {
            if (std.isTraceEnabled()) {
                std.trace("exit - " + SCEMethod.class.getName() + ".post()");
            }
            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug("POST --------------------------------------------------------> " + endpoint + resource);
            }
        }
    }

    public @Nullable String put(@Nonnull String resource, @Nullable List<NameValuePair> parameters)
            throws CloudException, InternalException {
        Logger std = SCE.getLogger(SCEMethod.class, "std");
        Logger wire = SCE.getLogger(SCEMethod.class, "wire");

        if (std.isTraceEnabled()) {
            std.trace("enter - " + SCEMethod.class.getName() + ".post(" + resource + ")");
        }
        if (wire.isDebugEnabled()) {
            wire.debug("POST --------------------------------------------------------> " + endpoint + resource);
            wire.debug("");
        }
        try {
            HttpClient client = getClient();

            HttpPut method = new HttpPut(endpoint + resource);

            method.addHeader("Content-Type", "application/x-www-form-urlencoded");
            method.addHeader("Accept", "text/xml");

            if (wire.isDebugEnabled()) {
                wire.debug(method.getRequestLine().toString());
                for (Header header : method.getAllHeaders()) {
                    wire.debug(header.getName() + ": " + header.getValue());
                }
                wire.debug("");
                if (parameters != null) {
                    Iterator<NameValuePair> it = parameters.iterator();
                    StringBuilder str = new StringBuilder();

                    while (it.hasNext()) {
                        NameValuePair p = it.next();

                        str.append(p.getName()).append("=").append(p.getValue());
                        if (it.hasNext()) {
                            str.append("&");
                        }
                    }
                    wire.debug(str.toString());
                    wire.debug("");
                }
            }
            if (parameters != null) {
                try {
                    method.setEntity(new UrlEncodedFormEntity(parameters, "utf-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new InternalException(e);
                }
            }
            HttpResponse response;
            StatusLine status;

            try {
                APITrace.trace(provider, resource);
                response = client.execute(method);
                status = response.getStatusLine();
            } catch (IOException e) {
                std.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage());
                if (std.isTraceEnabled()) {
                    e.printStackTrace();
                }
                throw new CloudException(e);
            }
            if (std.isDebugEnabled()) {
                std.debug("post(): HTTP Status " + status);
            }
            Header[] headers = response.getAllHeaders();

            if (wire.isDebugEnabled()) {
                wire.debug(status.toString());
                for (Header h : headers) {
                    if (h.getValue() != null) {
                        wire.debug(h.getName() + ": " + h.getValue().trim());
                    } else {
                        wire.debug(h.getName() + ":");
                    }
                }
                wire.debug("");
            }
            if (status.getStatusCode() != HttpServletResponse.SC_OK
                    && status.getStatusCode() != HttpServletResponse.SC_CREATED
                    && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED) {
                std.error("post(): Expected OK for GET request, got " + status.getStatusCode());

                HttpEntity entity = response.getEntity();
                String body;

                if (entity == null) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            "An error was returned without explanation");
                }
                try {
                    body = EntityUtils.toString(entity);
                } catch (IOException e) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            e.getMessage());
                }
                if (wire.isDebugEnabled()) {
                    wire.debug(body);
                }
                wire.debug("");
                throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                        body);
            } else if (status.getStatusCode() == HttpServletResponse.SC_NO_CONTENT) {
                return null;
            } else {
                HttpEntity entity = response.getEntity();

                if (entity == null) {
                    return null;
                }
                try {
                    return EntityUtils.toString(entity);
                } catch (IOException e) {
                    throw new SCEException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(),
                            e.getMessage());
                }
            }
        } finally {
            if (std.isTraceEnabled()) {
                std.trace("exit - " + SCEMethod.class.getName() + ".post()");
            }
            if (wire.isDebugEnabled()) {
                wire.debug("");
                wire.debug("POST --------------------------------------------------------> " + endpoint + resource);
            }
        }
    }
}