/** * Copyright (C) 2009-2015 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.joyent; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; 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.entity.ContentType; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import org.dasein.cloud.*; import org.dasein.security.joyent.*; public class JoyentMethod { static private final Logger logger = SmartDataCenter.getLogger(JoyentMethod.class, "std"); static private final Logger wire = SmartDataCenter.getLogger(JoyentMethod.class, "wire"); static private final ContentType APPLICATION_FORM_URLENCODED_UTF8 = ContentType.create("application/x-www-form-urlencoded", "UTF-8"); static private final ContentType APPLICATION_JSON_UTF8 = ContentType.create("application/json", "UTF-8"); static public final String VERSION = "~7.1"; private JoyentClientFactory clientFactory; private JoyentHttpAuth httpAuth; private RequestTrackingStrategy strategy; public JoyentMethod(@Nonnull SmartDataCenter provider) { this.clientFactory = new DefaultClientFactory(provider.getContext()); this.httpAuth = new SignatureHttpAuth(provider); this.strategy = provider.getContext().getRequestTrackingStrategy(); } public void doDelete(@Nonnull String endpoint, @Nonnull String resource) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doDelete(" + endpoint + "," + resource + ")"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [DELETE (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpDelete delete = new HttpDelete(endpoint + "/my/" + resource); httpAuth.addPreemptiveAuth(delete); delete.addHeader("Accept", "application/json"); delete.addHeader("X-Api-Version", VERSION); if(strategy != null && strategy.getSendAsHeader()){ delete.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code != HttpStatus.SC_NO_CONTENT && code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_CREATED ) { logger.error("Expected NO CONTENT for DELETE request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { wire.debug(""); } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doDelete()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [DELETE (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } public @Nullable String doGetJson(@Nonnull String endpoint, @Nonnull String resource) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doGetJson(" + endpoint + "," + resource + ")"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [GET (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpGet get = new HttpGet(endpoint + "/my/" + resource); httpAuth.addPreemptiveAuth(get); get.addHeader("Accept", "application/json"); get.addHeader("X-Api-Version", VERSION); if(strategy != null && strategy.getSendAsHeader()){ get.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code == HttpStatus.SC_NOT_FOUND || code == HttpStatus.SC_GONE ) { return null; } if( code != HttpStatus.SC_NO_CONTENT && code != HttpStatus.SC_OK && code != HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION ) { logger.error("Expected OK for GET request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { return null; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } return json; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doGetJson()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [GET (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } public @Nullable InputStream doGetStream(@Nonnull String endpoint, @Nonnull String resource) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doGetStream(" + endpoint + "," + resource + ")"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [GET (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpGet get = new HttpGet(endpoint + "/my/" + resource); httpAuth.addPreemptiveAuth(get); get.addHeader("Accept", "application/json"); get.addHeader("X-Api-Version", VERSION); if(strategy != null && strategy.getSendAsHeader()){ get.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code == HttpStatus.SC_NOT_FOUND ) { return null; } if( code != HttpStatus.SC_OK && code != HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION ) { logger.error("Expected OK for GET request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { return null; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { InputStream input; try { HttpEntity entity = response.getEntity(); if( entity == null ) { return null; } input = entity.getContent(); } catch( IOException e ) { logger.error("doGetStream(): Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( wire.isDebugEnabled() ) { wire.debug("---> Binary Data <---"); wire.debug(""); } return input; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doGetStream()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [GET (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } public @Nullable String doPostHeaders(@Nonnull String endpoint, @Nonnull String resource, @Nullable Map<String,String> customHeaders) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doPostHeaders(" + endpoint + "," + resource + "," + customHeaders + ")"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [POST (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpPost post = new HttpPost(endpoint + "/my/" + resource); httpAuth.addPreemptiveAuth(post); post.addHeader("Accept", "application/json"); post.addHeader("X-Api-Version", VERSION); if( customHeaders != null ) { for( Map.Entry<String, String> entry : customHeaders.entrySet() ) { String val = (entry.getValue() == null ? "" : entry.getValue()); post.addHeader(entry.getKey(), val); } } if(strategy != null && strategy.getSendAsHeader()){ post.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_NO_CONTENT && code != HttpStatus.SC_CREATED ) { logger.error("Expected ACCEPTED for POST request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { if( code == HttpStatus.SC_ACCEPTED || code == HttpStatus.SC_CREATED ) { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( json != null && !json.trim().equals("") ) { return json; } } return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doPostHeaders()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [POST (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } public @Nullable String doPostString(@Nonnull String endpoint, @Nonnull String resource, @Nullable String payload) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doPostString(" + endpoint + "," + resource + ",PAYLOAD)"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [POST (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpPost post = new HttpPost(endpoint + "/my/" + resource); httpAuth.addPreemptiveAuth(post); if( payload != null && payload.startsWith("action") ) { post.addHeader("Content-Type", "application/x-www-form-urlencoded"); } else { post.addHeader("Content-Type", "application/json"); } post.addHeader("Accept", "application/json"); post.addHeader("X-Api-Version", VERSION); if(strategy != null && strategy.getSendAsHeader()){ post.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } if( payload != null && payload.startsWith("action") ) { post.setEntity(new StringEntity(payload, APPLICATION_FORM_URLENCODED_UTF8)); } else { post.setEntity(new StringEntity(payload == null ? "" : payload, APPLICATION_JSON_UTF8)); } 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_NO_CONTENT && code != HttpStatus.SC_CREATED && code != HttpStatus.SC_OK ) { logger.error("Expected ACCEPTED for POST request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { if( code == HttpStatus.SC_ACCEPTED || code == HttpStatus.SC_CREATED || code == HttpStatus.SC_OK ) { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( json != null && !json.trim().equals("") ) { return json; } } return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doPostString()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [POST (" + (new Date()) + ")] -> " + endpoint + "/my/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } public @Nullable String doPostStream(@Nonnull String endpoint, @Nonnull String resource, @Nullable String md5Hash, @Nullable InputStream stream) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doPostStream(" + endpoint + "," + resource + "," + md5Hash + ",PAYLOAD)"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [POST (" + (new Date()) + ")] -> " + endpoint + "/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpPost post = new HttpPost(endpoint + resource); httpAuth.addPreemptiveAuth(post); post.addHeader("Content-Type", "application/octet-stream"); post.addHeader("Accept", "application/json"); post.addHeader("X-Api-Version", VERSION); if(strategy != null && strategy.getSendAsHeader()){ post.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } post.setEntity(new InputStreamEntity(stream, -1L, ContentType.APPLICATION_OCTET_STREAM)); if( wire.isDebugEnabled() ) { wire.debug(post.getRequestLine().toString()); for( Header header : post.getAllHeaders() ) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); wire.debug("--> BINARY DATA <--"); 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); String responseHash = null; for( Header h : response.getAllHeaders() ) { if( h.getName().equals("ETag") ) { responseHash = h.getValue(); } } if( responseHash != null && md5Hash != null && !responseHash.equals(md5Hash) ) { throw new CloudException("MD5 hash values do not match, probably data corruption"); } if( code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_NO_CONTENT && code != HttpStatus.SC_CREATED ) { logger.error("Expected ACCEPTED or NO CONTENT for POST request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { wire.debug(""); if( code == HttpStatus.SC_ACCEPTED || code == HttpStatus.SC_CREATED ) { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( json != null && !json.trim().equals("") ) { return json; } } return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doPostStream()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [POST (" + (new Date()) + ")] -> " + endpoint + "/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } protected @Nullable String putHeaders(@Nonnull String authToken, @Nonnull String endpoint, @Nonnull String resource, @Nullable Map<String,String> customHeaders) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doPutHeaders(" + endpoint + "," + resource + "," + customHeaders + ")"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [PUT (" + (new Date()) + ")] -> " + endpoint + "/" + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpPut put = new HttpPut(endpoint + resource); put.addHeader("Content-Type", "application/json"); put.addHeader("Accept", "application/json"); put.addHeader("X-Auth-Token", authToken); if( customHeaders != null ) { for( Map.Entry<String, String> entry : customHeaders.entrySet() ) { String val = (entry.getValue() == null ? "" : entry.getValue()); put.addHeader(entry.getKey(), val); } } if(strategy != null && strategy.getSendAsHeader()){ put.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code != HttpStatus.SC_CREATED && code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_NO_CONTENT ) { logger.error("Expected CREATED, ACCEPTED, or NO CONTENT for put request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { if( code == HttpStatus.SC_ACCEPTED || code == HttpStatus.SC_CREATED ) { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( json != null && !json.trim().equals("") ) { return json; } } return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doPutHeaders()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [PUT (" + (new Date()) + ")] -> " + endpoint + "/" + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } protected String putString(@Nonnull String authToken, @Nonnull String endpoint, @Nonnull String resource, @Nullable String payload) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doPutString(" + endpoint + "," + resource + ",PAYLOAD)"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [PUT (" + (new Date()) + ")] -> " + endpoint + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpPut put = new HttpPut(endpoint + resource); put.addHeader("Content-Type", "application/json"); put.addHeader("Accept", "application/json"); put.addHeader("X-Auth-Token", authToken); if(strategy != null && strategy.getSendAsHeader()){ put.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } put.setEntity(new StringEntity(payload == null ? "" : payload, APPLICATION_JSON_UTF8)); 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); if( code != HttpStatus.SC_CREATED && code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_NO_CONTENT ) { logger.error("Expected CREATED, ACCEPTED, or NO CONTENT for put request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { if( code == HttpStatus.SC_ACCEPTED || code == HttpStatus.SC_CREATED ) { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( json != null && !json.trim().equals("") ) { return json; } } return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doPutString()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [PUT (" + (new Date()) + ")] -> " + endpoint + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } protected @Nullable String putStream(@Nonnull String authToken, @Nonnull String endpoint, @Nonnull String resource, @Nullable String md5Hash, @Nullable InputStream stream) throws CloudException, InternalException { if( logger.isTraceEnabled() ) { logger.trace("ENTER - " + JoyentMethod.class.getName() + ".doPutStream(" + endpoint + "," + resource + "," + md5Hash + ",PAYLOAD)"); } if( wire.isDebugEnabled() ) { wire.debug(""); wire.debug(">>> [PUT (" + (new Date()) + ")] -> " + endpoint + resource + " >--------------------------------------------------------------------------------------"); } try { HttpClient client = clientFactory.getClient(endpoint); HttpPut put = new HttpPut(endpoint + resource); put.addHeader("Content-Type", "application/octet-stream"); put.addHeader("Accept", "application/json"); put.addHeader("X-Auth-Token", authToken); if( md5Hash != null ) { put.addHeader("ETag", md5Hash); } if(strategy != null && strategy.getSendAsHeader()){ put.addHeader(strategy.getHeaderName(), strategy.getRequestId()); } put.setEntity(new InputStreamEntity(stream, -1L, ContentType.APPLICATION_OCTET_STREAM)); if( wire.isDebugEnabled() ) { wire.debug(put.getRequestLine().toString()); for( Header header : put.getAllHeaders() ) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); wire.debug("--> BINARY DATA <--"); 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()); throw new InternalException(e); } int code = response.getStatusLine().getStatusCode(); logger.debug("HTTP STATUS: " + code); String responseHash = null; for( Header h : response.getAllHeaders() ) { if( h.getName().equals("ETag") ) { responseHash = h.getValue(); } } if( responseHash != null && md5Hash != null && !responseHash.equals(md5Hash) ) { throw new CloudException("MD5 hash values do not match, probably data corruption"); } if( code != HttpStatus.SC_CREATED && code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_NO_CONTENT ) { logger.error("Expected CREATED, ACCEPTED, or NO CONTENT for PUT request, got " + code); String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } JoyentException.ExceptionItems items = JoyentException.parseException(code, json); if( items == null ) { items = new JoyentException.ExceptionItems(); items.code = 404; items.type = CloudErrorType.COMMUNICATION; items.message = "itemNotFound"; items.details = "No such object: " + resource; } logger.error("[" + code + " : " + items.message + "] " + items.details); throw new JoyentException(items); } else { if( code == HttpStatus.SC_ACCEPTED ) { String json = null; try { HttpEntity entity = response.getEntity(); if( entity != null ) { json = EntityUtils.toString(entity); if( wire.isDebugEnabled() ) { wire.debug(json); wire.debug(""); } } } catch( IOException e ) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } if( json != null && !json.trim().equals("") ) { return json; } } return null; } } finally { if( logger.isTraceEnabled() ) { logger.trace("EXIT - " + JoyentMethod.class.getName() + ".doPutStream()"); } if( wire.isDebugEnabled() ) { wire.debug("<<< [PUT (" + (new Date()) + ")] -> " + endpoint + resource + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } } }