Java tutorial
/** * Copyright (C) 2013-2015 Dell, 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.azure; import org.apache.commons.codec.binary.Base64; 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.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpTrace; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.FileEntity; 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.CloudErrorType; import org.dasein.cloud.CloudException; import org.dasein.cloud.InternalException; import org.dasein.cloud.ProviderContext; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.TimeZone; import java.util.TreeMap; import java.util.TreeSet; /** * Handles connectivity to Microsoft Azure Storage services. * @author George Reese (george.reese@imaginary.com) * @author Qunying Huang (qunying.huang@enstratus.com) * @author Danielle Mayne (danielle.mayne@enstratius.com) * @since 2012.07.1 * @version 2013.04.1 */ public class AzureStorageMethod { static private final Logger logger = Azure.getLogger(AzureStorageMethod.class); static private final Logger wire = Azure.getWireLogger(AzureStorageMethod.class); static public final String VERSION = "2009-09-19"; //static public final String VERSION = "2012-02-12"; private String Header_Prefix_MS = "x-ms-"; public static final String Storage_OPERATION_DELETE = "DELETE"; public static final String Storage_OPERATION_PUT = "PUT"; public static final String Storage_OPERATION_GET = "GET"; private Azure provider; public AzureStorageMethod(Azure azure) throws AzureConfigException { provider = azure; ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new AzureConfigException("No context was provided for this request"); } } private void fetchKeys() throws CloudException, InternalException { ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } if (ctx.getStoragePrivate() == null) { AzureMethod method = new AzureMethod(provider); String storageService = provider.getStorageService(); if (storageService == null || storageService.isEmpty()) { throw new CloudException( "Unable to find storage service in the current region: " + ctx.getRegionId()); } Document doc = method.getAsXML(ctx.getAccountNumber(), "/services/storageservices/" + storageService + "/keys"); if (doc == null) { throw new CloudException("Unable to identify the storage keys for this account"); } NodeList keys = doc.getElementsByTagName("StorageServiceKeys"); for (int i = 0; i < keys.getLength(); i++) { Node key = keys.item(i); if (key.getNodeName().equalsIgnoreCase("StorageServiceKeys") && key.hasChildNodes()) { NodeList parts = key.getChildNodes(); String p = null, s = null; for (int j = 0; j < parts.getLength(); j++) { Node part = parts.item(j); if (part.getNodeName().equalsIgnoreCase("primary") && part.hasChildNodes()) { p = part.getFirstChild().getNodeValue().trim(); } else if (part.getNodeName().equalsIgnoreCase("secondary") && part.hasChildNodes()) { s = part.getFirstChild().getNodeValue().trim(); } } if (p != null) { try { ctx.setStoragePrivate(p.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { logger.error("UTF-8 not supported: " + e.getMessage()); throw new InternalException(e); } break; } else if (s != null) { try { ctx.setStoragePrivate(s.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { logger.error("UTF-8 not supported: " + e.getMessage()); throw new InternalException(e); } break; } } } } } private String getStorageAccount() throws CloudException, InternalException { return provider.getStorageService(); } private String calculatedSharedKeyLiteSignature(@Nonnull HttpRequestBase method, @Nonnull Map<String, String> queryParams) throws CloudException, InternalException { fetchKeys(); ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new AzureConfigException("No context was specified for this request"); } Header h = method.getFirstHeader("content-type"); String contentType = (h == null ? null : h.getValue()); if (contentType == null) { contentType = ""; } StringBuilder stringToSign = new StringBuilder(); stringToSign.append(method.getMethod().toUpperCase()).append("\n"); stringToSign.append("\n"); // content-md5 stringToSign.append(contentType).append("\n"); stringToSign.append(method.getFirstHeader("date").getValue()).append("\n"); Header[] headers = method.getAllHeaders(); TreeSet<String> keys = new TreeSet<String>(); for (Header header : headers) { if (header.getName().startsWith(Header_Prefix_MS)) { keys.add(header.getName().toLowerCase()); } } for (String key : keys) { Header header = method.getFirstHeader(key); if (header != null) { Header[] all = method.getHeaders(key); stringToSign.append(key.toLowerCase().trim()).append(":"); if (all != null && all.length > 0) { for (Header current : all) { String v = (current.getValue() != null ? current.getValue() : ""); stringToSign.append(v.trim().replaceAll("\n", " ")).append(","); } } stringToSign.deleteCharAt(stringToSign.lastIndexOf(",")); } else { stringToSign.append(key.toLowerCase().trim()).append(":"); } stringToSign.append("\n"); } stringToSign.append("/").append(getStorageAccount()).append(method.getURI().getPath()); keys.clear(); for (String key : queryParams.keySet()) { if (key.equalsIgnoreCase("comp")) { key = key.toLowerCase(); keys.add(key); } } if (!keys.isEmpty()) { stringToSign.append("?"); for (String key : keys) { String value = queryParams.get(key); if (value == null) { value = ""; } stringToSign.append(key).append("=").append(value).append("&"); } stringToSign.deleteCharAt(stringToSign.lastIndexOf("&")); } try { if (logger.isDebugEnabled()) { logger.debug("BEGIN STRING TO SIGN"); logger.debug(stringToSign.toString()); logger.debug("END STRING TO SIGN"); } Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(Base64.decodeBase64(ctx.getStoragePrivate()), "HmacSHA256")); String signature = new String( Base64.encodeBase64(mac.doFinal(stringToSign.toString().getBytes("UTF-8")))); if (logger.isDebugEnabled()) { logger.debug("signature=" + signature); } return signature; } catch (UnsupportedEncodingException e) { logger.error("UTF-8 not supported: " + e.getMessage()); throw new InternalException(e); } catch (NoSuchAlgorithmException e) { logger.error("No such algorithm: " + e.getMessage()); throw new InternalException(e); } catch (InvalidKeyException e) { logger.error("Invalid key: " + e.getMessage()); throw new InternalException(e); } } public static Document createDoc() throws InternalException { try { return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); } catch (ParserConfigurationException e) { throw new InternalException(e); } } /** * Convert a xml document to string */ @SuppressWarnings("unused") public static String convertDomToString(Document doc) throws CloudException, InternalException { try { if (doc == null) return null; StringWriter stw = new StringWriter(); Transformer serializer = TransformerFactory.newInstance().newTransformer(); serializer.transform(new DOMSource(doc), new StreamResult(stw)); if (stw != null) { return stw.toString(); } return null; } catch (TransformerConfigurationException e) { throw new InternalException(e); } catch (TransformerFactoryConfigurationError e) { throw new InternalException(e); } catch (TransformerException e) { throw new InternalException(e); } } @SuppressWarnings("deprecation") public Document getAsDoc(@Nonnull String httpVerb, @Nonnull String resource, @Nullable Map<String, String> queries, @Nullable String body, @Nullable Map<String, String> headerMap, boolean authorization) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("enter - " + AzureStorageMethod.class.getName() + "." + httpVerb + "(" + getStorageAccount() + "," + resource + ")"); } String endpoint = getStorageEnpoint(); if (wire.isDebugEnabled()) { wire.debug(httpVerb + "--------------------------------------------------------> " + endpoint + getStorageAccount() + resource); wire.debug(""); } try { HttpClient client = getClient(); if (headerMap == null) { headerMap = new HashMap<String, String>(); } HttpRequestBase method = getMethod(httpVerb, buildUrl(resource, queries), queries, headerMap, authorization); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); if (body != null) { wire.debug(body); wire.debug(""); } } // If it is post or put if (method instanceof HttpEntityEnclosingRequestBase) { HttpEntityEnclosingRequestBase entityEnclosingMethod = (HttpEntityEnclosingRequestBase) method; if (body != null) { entityEnclosingMethod.setEntity(new StringEntity(body, "application/xml", "utf-8")); } } HttpResponse response; StatusLine status; try { response = client.execute(method); status = response.getStatusLine(); } catch (IOException e) { logger.error("GET(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } if (logger.isDebugEnabled()) { logger.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) { logger.error( httpVerb + "(): Expected OK for " + httpVerb + "request, got " + status.getStatusCode()); HttpEntity entity = response.getEntity(); String result; if (entity == null) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), "An error was returned without explanation"); } try { result = EntityUtils.toString(entity); } catch (IOException e) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } if (wire.isDebugEnabled()) { wire.debug(result); } wire.debug(""); AzureException.ExceptionItems items = AzureException.parseException(status.getStatusCode(), result); if (items == null) { return null; } logger.error( httpVerb + "(): [" + status.getStatusCode() + " : " + items.message + "] " + items.details); throw new AzureException(items); } else { HttpEntity entity = response.getEntity(); if (entity == null) { return null; } InputStream input; try { input = entity.getContent(); } catch (IOException e) { logger.error(httpVerb + "(): Failed to read response error due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } return parseResponse(input, true); } } catch (UnsupportedEncodingException e) { throw new CloudException(e); } finally { if (logger.isTraceEnabled()) { logger.trace("exit - " + AzureMethod.class.getName() + ".getStream()"); } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug("--------------------------------------------------------> "); } } } public @Nullable InputStream getAsStream(@Nonnull String strMethod, @Nonnull String resource, @Nonnull Map<String, String> queries, @Nullable String body, @Nullable Map<String, String> headerMap, boolean authorization) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("enter - " + AzureStorageMethod.class.getName() + "." + strMethod + "(" + getStorageAccount() + "," + resource + ")"); } String endpoint = getStorageEnpoint(); if (wire.isDebugEnabled()) { wire.debug(strMethod + "--------------------------------------------------------> " + endpoint + getStorageAccount() + resource); wire.debug(""); } try { HttpClient client = getClient(); String contentLength = null; if (body != null) { contentLength = String.valueOf(body.length()); } else { contentLength = "0"; } HttpRequestBase method = getMethod(strMethod, buildUrl(resource, queries), queries, headerMap, authorization); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); if (body != null) { wire.debug(body); wire.debug(""); } } // If it is post or put if (method instanceof HttpEntityEnclosingRequestBase) { HttpEntityEnclosingRequestBase entityEnclosingMethod = (HttpEntityEnclosingRequestBase) method; if (body != null) { entityEnclosingMethod.setEntity(new StringEntity(body, "application/xml", "utf-8")); } } HttpResponse response; StatusLine status; try { response = client.execute(method); status = response.getStatusLine(); } catch (IOException e) { logger.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } if (logger.isDebugEnabled()) { logger.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_NOT_FOUND) { return null; } if (status.getStatusCode() != HttpServletResponse.SC_OK && status.getStatusCode() != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION) { logger.error( strMethod + "(): Expected OK for " + strMethod + "request, got " + status.getStatusCode()); HttpEntity entity = response.getEntity(); String result; if (entity == null) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), "An error was returned without explanation"); } try { result = EntityUtils.toString(entity); } catch (IOException e) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } if (wire.isDebugEnabled()) { wire.debug(result); } wire.debug(""); AzureException.ExceptionItems items = AzureException.parseException(status.getStatusCode(), result); if (items == null) { return null; } logger.error(strMethod + "(): [" + status.getStatusCode() + " : " + items.message + "] " + items.details); throw new AzureException(items); } else { HttpEntity entity = response.getEntity(); if (entity == null) { return null; } InputStream input; try { input = entity.getContent(); } catch (IOException e) { logger.error(strMethod + "(): Failed to read response error due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } return input; } } catch (UnsupportedEncodingException e) { throw new CloudException(e); } finally { if (logger.isTraceEnabled()) { logger.trace("exit - " + AzureMethod.class.getName() + ".getStream()"); } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug("--------------------------------------------------------> "); } } } protected @Nonnull HttpClient getClient() throws InternalException, CloudException { ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new AzureConfigException("No context was defined for this request"); } String endpoint = getStorageEnpoint(); boolean ssl = endpoint.startsWith("https"); int targetPort; try { URI uri = new URI(endpoint); targetPort = uri.getPort(); if (targetPort < 1) { targetPort = (ssl ? 443 : 80); } } catch (URISyntaxException e) { throw new AzureConfigException(e); } HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); 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); } public @Nonnull Document parseResponse(@Nonnull String responseBody, boolean withWireLogging) throws CloudException, InternalException { 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, "UTF-8")); StringBuilder sb = new StringBuilder(); String line; while ((line = in.readLine()) != null) { sb.append(line); sb.append("\n"); } in.close(); // The response may start with ? instead of < String strResponse = sb.toString(); int index = strResponse.indexOf("<"); if (index > 0) { return parseResponse(strResponse.substring(index), withWireLogging); } else { return parseResponse(strResponse, withWireLogging); } } catch (IOException e) { throw new CloudException(e); } } public String buildUrl(String resource, Map<String, String> queries) throws InternalException, CloudException { String endpoint = getStorageEnpoint(); StringBuilder str = new StringBuilder(); str.append(endpoint); if (!endpoint.endsWith("/")) { str.append("/"); } if (resource != null && !resource.equalsIgnoreCase("null")) { str.append(resource); } if (queries != null && queries.size() > 0) { str.append("?"); } boolean firstPara = true; if (queries != null) { //comp key should be put first if (queries.containsKey("comp")) { str.append("comp"); str.append("="); str.append(queries.get("comp")); firstPara = false; } for (String key : queries.keySet()) { if (key.equals("comp")) continue; if (firstPara) { str.append(key); str.append("="); str.append(queries.get(key)); firstPara = false; } else { str.append("&"); str.append(key); str.append("="); str.append(queries.get(key)); } } } return str.toString(); } public String getBlobProperty(@Nonnull String strMethod, @Nonnull String resource, @Nonnull Map<String, String> queries, String body, @Nullable Map<String, String> headerMap, boolean authorization, String propertyName) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("enter - " + AzureStorageMethod.class.getName() + "." + strMethod + "(" + getStorageAccount() + "," + resource + ")"); } String endpoint = getStorageEnpoint(); if (wire.isDebugEnabled()) { wire.debug(strMethod + "--------------------------------------------------------> " + endpoint + getStorageAccount() + resource); wire.debug(""); } try { HttpClient client = getClient(); if (headerMap == null) { headerMap = new HashMap<String, String>(); } HttpRequestBase method = getMethod(strMethod, buildUrl(resource, queries), queries, headerMap, authorization); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); if (body != null) { wire.debug(body); wire.debug(""); } } // If it is post or put if (method instanceof HttpEntityEnclosingRequestBase) { HttpEntityEnclosingRequestBase entityEnclosingMethod = (HttpEntityEnclosingRequestBase) method; if (body != null) { entityEnclosingMethod.setEntity(new StringEntity(body, "application/xml", "utf-8")); } } HttpResponse response; StatusLine status; try { response = client.execute(method); status = response.getStatusLine(); } catch (IOException e) { logger.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } if (logger.isDebugEnabled()) { logger.debug("get(): HTTP Status " + status); } if (wire.isDebugEnabled()) { Header[] headers = response.getAllHeaders(); 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_CREATED && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED && status.getStatusCode() != HttpServletResponse.SC_OK) && status.getStatusCode() != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION) { logger.error( strMethod + "(): Expected OK for " + strMethod + "request, got " + status.getStatusCode()); HttpEntity entity = response.getEntity(); String result; if (entity == null) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), "An error was returned without explanation"); } try { result = EntityUtils.toString(entity); int index = result.indexOf("<"); // The result may not be a stardard xml format if (index > 0) { result = result.substring(index); } } catch (IOException e) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } if (wire.isDebugEnabled()) { wire.debug(result); } wire.debug(""); AzureException.ExceptionItems items = AzureException.parseException(status.getStatusCode(), result); logger.error(strMethod + "(): [" + status.getStatusCode() + " : " + items.message + "] " + items.details); throw new AzureException(items); } else { Header header = response.getFirstHeader(propertyName); if (header != null) { return header.getValue(); } else { return null; } } } catch (UnsupportedEncodingException e) { throw new CloudException(e); } finally { if (logger.isTraceEnabled()) { logger.trace("exit - " + AzureMethod.class.getName() + ".getStream()"); } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug("--------------------------------------------------------> "); } } } public void invoke(@Nonnull String strMethod, @Nonnull String resource, @Nonnull Map<String, String> queries, @Nullable String body, @Nullable Map<String, String> headerMap, boolean authorization) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("enter - " + AzureStorageMethod.class.getName() + "." + strMethod + "(" + getStorageAccount() + "," + resource + ")"); } String endpoint = getStorageEnpoint(); if (wire.isDebugEnabled()) { wire.debug(strMethod + "--------------------------------------------------------> " + endpoint + getStorageAccount() + resource); wire.debug(""); } try { HttpClient client = getClient(); if (headerMap == null) { headerMap = new HashMap<String, String>(); } HttpRequestBase method = getMethod(strMethod, buildUrl(resource, queries), queries, headerMap, authorization); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); if (body != null) { wire.debug(body); wire.debug(""); } } // If it is post or put if (method instanceof HttpEntityEnclosingRequestBase) { HttpEntityEnclosingRequestBase entityEnclosingMethod = (HttpEntityEnclosingRequestBase) method; if (body != null) { entityEnclosingMethod.setEntity(new StringEntity(body, "application/xml", "utf-8")); } } HttpResponse response; StatusLine status; try { response = client.execute(method); status = response.getStatusLine(); } catch (IOException e) { logger.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } if (logger.isDebugEnabled()) { logger.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_CREATED && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED && status.getStatusCode() != HttpServletResponse.SC_OK) && status.getStatusCode() != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION) { logger.error( strMethod + "(): Expected OK for " + strMethod + "request, got " + status.getStatusCode()); HttpEntity entity = response.getEntity(); String result; if (entity == null) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), "An error was returned without explanation"); } try { result = EntityUtils.toString(entity); } catch (IOException e) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } if (wire.isDebugEnabled()) { wire.debug(result); } wire.debug(""); AzureException.ExceptionItems items = AzureException.parseException(status.getStatusCode(), result); if (items != null) { logger.error(strMethod + "(): [" + status.getStatusCode() + " : " + items.message + "] " + items.details); throw new AzureException(items); } else { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), "UnknownError", result); } } } catch (UnsupportedEncodingException e) { throw new CloudException(e); } finally { if (logger.isTraceEnabled()) { logger.trace("exit - " + AzureMethod.class.getName() + ".getStream()"); } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug("--------------------------------------------------------> "); } } } public void putWithFile(@Nonnull String strMethod, @Nonnull String resource, Map<String, String> queries, File file, Map<String, String> headerMap, boolean authorization) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("enter - " + AzureStorageMethod.class.getName() + "." + strMethod + "(" + getStorageAccount() + "," + resource + ")"); } String endpoint = getStorageEnpoint(); if (wire.isDebugEnabled()) { wire.debug(strMethod + "--------------------------------------------------------> " + endpoint + getStorageAccount() + resource); wire.debug(""); } long begin = System.currentTimeMillis(); try { HttpClient client = getClient(); String contentLength = null; if (file != null) { contentLength = String.valueOf(file.length()); } else { contentLength = "0"; } HttpRequestBase method = getMethod(strMethod, buildUrl(resource, queries), queries, headerMap, authorization); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); if (file != null) { wire.debug(file); wire.debug(""); } } // If it is post or put if (method instanceof HttpEntityEnclosingRequestBase) { HttpEntityEnclosingRequestBase entityEnclosingMethod = (HttpEntityEnclosingRequestBase) method; if (file != null) { entityEnclosingMethod.setEntity(new FileEntity(file, ContentType.APPLICATION_OCTET_STREAM)); } } HttpResponse response; StatusLine status; try { response = client.execute(method); status = response.getStatusLine(); } catch (IOException e) { logger.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } long end = System.currentTimeMillis(); logger.debug("Totoal time -> " + (end - begin)); throw new CloudException(e); } if (logger.isDebugEnabled()) { logger.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_CREATED && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED && status.getStatusCode() != HttpServletResponse.SC_OK) && status.getStatusCode() != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION) { logger.error( strMethod + "(): Expected OK for " + strMethod + "request, got " + status.getStatusCode()); HttpEntity entity = response.getEntity(); String result; if (entity == null) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), "An error was returned without explanation"); } try { result = EntityUtils.toString(entity); } catch (IOException e) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } if (wire.isDebugEnabled()) { wire.debug(result); } wire.debug(""); AzureException.ExceptionItems items = AzureException.parseException(status.getStatusCode(), result); logger.error(strMethod + "(): [" + status.getStatusCode() + " : " + items.message + "] " + items.details); throw new AzureException(items); } } finally { if (logger.isTraceEnabled()) { logger.trace("exit - " + AzureMethod.class.getName() + ".getStream()"); } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug("--------------------------------------------------------> "); } } } public void putWithBytes(@Nonnull String strMethod, @Nonnull String resource, Map<String, String> queries, byte[] body, Map<String, String> headerMap, boolean authorization) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("enter - " + AzureStorageMethod.class.getName() + "." + strMethod + "(" + getStorageAccount() + "," + resource + ")"); } String endpoint = getStorageEnpoint(); if (wire.isDebugEnabled()) { wire.debug(strMethod + "--------------------------------------------------------> " + endpoint + getStorageAccount() + resource); wire.debug(""); } try { HttpClient client = getClient(); String contentLength = null; if (body != null) { contentLength = String.valueOf(body.length); } else { contentLength = "0"; } HttpRequestBase method = getMethod(strMethod, buildUrl(resource, queries), queries, headerMap, authorization); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); if (body != null) { wire.debug(body); wire.debug(""); } } // If it is post or put if (method instanceof HttpEntityEnclosingRequestBase) { HttpEntityEnclosingRequestBase entityEnclosingMethod = (HttpEntityEnclosingRequestBase) method; if (body != null) { entityEnclosingMethod.setEntity(new ByteArrayEntity(body)); } } HttpResponse response; StatusLine status; try { response = client.execute(method); status = response.getStatusLine(); } catch (IOException e) { logger.error("post(): Failed to execute HTTP request due to a cloud I/O error: " + e.getMessage()); if (logger.isTraceEnabled()) { e.printStackTrace(); } throw new CloudException(e); } if (logger.isDebugEnabled()) { logger.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_CREATED && status.getStatusCode() != HttpServletResponse.SC_ACCEPTED && status.getStatusCode() != HttpServletResponse.SC_OK) && status.getStatusCode() != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION) { logger.error( strMethod + "(): Expected OK for " + strMethod + "request, got " + status.getStatusCode()); HttpEntity entity = response.getEntity(); String result; if (entity == null) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), "An error was returned without explanation"); } try { result = EntityUtils.toString(entity); } catch (IOException e) { throw new AzureException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } if (wire.isDebugEnabled()) { wire.debug(result); } wire.debug(""); AzureException.ExceptionItems items = AzureException.parseException(status.getStatusCode(), result); logger.error(strMethod + "(): [" + status.getStatusCode() + " : " + items.message + "] " + items.details); throw new AzureException(items); } } finally { if (logger.isTraceEnabled()) { logger.trace("exit - " + AzureMethod.class.getName() + ".getStream()"); } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug("--------------------------------------------------------> "); } } } protected HttpRequestBase getMethod(@Nonnull String httpMethod, @Nonnull String endpoint, @Nonnull Map<String, String> queryParams, @Nullable Map<String, String> headers, boolean authorization) throws CloudException, InternalException { HttpRequestBase method; if (httpMethod.equals("GET")) { method = new HttpGet(endpoint); } else if (httpMethod.equals("POST")) { method = new HttpPost(endpoint); } else if (httpMethod.equals("PUT")) { method = new HttpPut(endpoint); } else if (httpMethod.equals("DELETE")) { method = new HttpDelete(endpoint); } else if (httpMethod.equals("HEAD")) { method = new HttpHead(endpoint); } else if (httpMethod.equals("OPTIONS")) { method = new HttpOptions(endpoint); } else if (httpMethod.equals("HEAD")) { method = new HttpTrace(endpoint); } else { method = new HttpGet(endpoint); } if (!authorization) { return method; } if (headers == null) { headers = new TreeMap<String, String>(); } String RFC1123_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z"; DateFormat rfc1123Format = new SimpleDateFormat(RFC1123_PATTERN); rfc1123Format.setTimeZone(TimeZone.getTimeZone("GMT")); headers.put("Date", rfc1123Format.format(new Date())); headers.put(Header_Prefix_MS + "version", VERSION); for (String key : headers.keySet()) { method.addHeader(key, headers.get(key)); } if (method.getFirstHeader("content-type") == null && !httpMethod.equals("GET")) { method.addHeader("content-type", "application/xml;charset=utf-8"); } method.addHeader("Authorization", "SharedKeyLite " + getStorageAccount() + ":" + calculatedSharedKeyLiteSignature(method, queryParams)); return method; } private String getStorageEnpoint() throws CloudException, InternalException { String storageEndpoint = provider.getStorageEndpoint(); if (storageEndpoint == null || storageEndpoint.isEmpty()) { throw new CloudException("Cannot find blob storage endpoint in the current region"); } return storageEndpoint; } }