//2012-12-05 johnpfeiffer
package net.kittyandbear;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.rmi.UnexpectedException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class NirvanixStorageConnector {
enum DataTransferProtocol {
HTTP,
HTTPS
};
private static final Logger logger = Logger.getLogger( NirvanixStorageConnector.class.getName() );
protected static HttpClient httpclient = null;
private String clientPreferedDataTransferProtocol = "https";
private String apiHostname;
private int maxConnectionsPerRoute = 2; // Apache's default
private int maxConnectionsOverall = 10; // Apache's default
// Example Nirvanix API request format http://services.nirvanix.com/ws/{NameSpace}/MethodName.ashx?name=value&name2=value2
private static final String LOGIN = "/ws/Authentication/Login.ashx";
protected static final String UPLOAD = "/Upload.ashx";
protected static final String GET_UPLOAD_TOKEN = "/ws/IMFS/GetStorageNodeExtended.ashx";
private static final String GET_DOWNLOAD_TOKEN = "/ws/IMFS/GetOptimalUrls.ashx";
private static final String GET_METADATA = "/ws/Metadata/GetMetadata.ashx";
private static final String DELETE = "/ws/IMFS/DeleteFiles.ashx";
private static final int DOWNLOAD_TOKEN_EXPIRATION_IN_SECONDS = 1800;
public void setHttps( boolean isHttps ) {
// Note if https is false, caller must explicitly deal with secure data transfer by its own
clientPreferedDataTransferProtocol = isHttps ? "https" : "http";
}
public void setApiHostname( String apiHostname ) {
this.apiHostname = apiHostname;
}
public void setMaxConnectionsPerRoute( int maxConnectionsPerRoute ) {
// Maximum concurrent connections per route
this.maxConnectionsPerRoute = maxConnectionsPerRoute > 0 ? maxConnectionsPerRoute : this.maxConnectionsPerRoute;
}
public void setMaxConnectionsOverall( int maxConnectionsOverall ) {
// Maximum concurrent connections for all routes used by httpClient
this.maxConnectionsOverall = maxConnectionsOverall > 0 ? maxConnectionsOverall : this.maxConnectionsOverall;
}
/* During creation you explicitly choose a Nirvanix Service Provider (e.g. IBM's apiHostname) and whether data is transferred with HTTP or HTTPS */
public void initialization() throws SystemException {
if( isNullOrEmpty( apiHostname ) ) {
throw new SystemException( ResponseCategory.InvalidInputConstructorApiHostname.code,
"ERROR: Cannot instantiate as constructor was given an invalid apiHostname" );
}
HttpClientFactory myHttpClientFactory = HttpClientFactory.getInstance();
myHttpClientFactory.setMaxConnectionsPerRoute( maxConnectionsPerRoute );
myHttpClientFactory.setMaxConnectionsOverall( maxConnectionsOverall );
NirvanixStorageConnector.httpclient = HttpClientFactory.getStaticHttpClient();
}
public String getSession( String appKey, String username, String password ) throws RuleException, SystemException, IOException,
UnexpectedException {
if( isNullOrEmpty( appKey ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetSessionAppKey.code, "ERROR: Cannot get session as appkey is not valid" );
}
if( isNullOrEmpty( username ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetSessionUsername.code,
"ERROR: Cannot get session as username is not valid" );
}
if( isNullOrEmpty( password ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetSessionPassword.code,
"ERROR: Cannot get session as password is not valid" );
}
// Build the correct URI to get the sessionToken from Nirvanix (in JSON format) - Critical call uses https
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme( "https" ).setHost( this.apiHostname ).setPath( LOGIN ).setParameter( "appKey", appKey )
.setParameter( "username", username ).setParameter( "password", password ).setParameter( "output", "json" );
String response = executeHttp( uriBuilder ); // Use a private helper method to get the response as a String (JSON)
try {
JSONObject responseJSON = new JSONObject( response );
assertValidNirvanixResponse( responseJSON.getString( "ResponseCode" ) );
String sessionToken = responseJSON.getString( "SessionToken" );
logger.debug( "New sessionToken = " + sessionToken );
return sessionToken;
} catch( JSONException e ) {
throw new UnexpectedException( ResponseCategory.JSONSyntaxExceptionGetSession.code
+ ",ERROR: Get session recieved a JSON Exception " + e.getMessage() );
}
}
/**
* Put a file as stream to remote storage. Return fileId on success, throw exception if otherwise.
*
* Nirvanix REST parameters for GetStorageNodeExtended (returns one token per upload, the token returned will expire after 72 hours) https ://{apiHostName}/ws/IMFS/GetStorageNodeExtended.ashx?sessionToken={sessionToken}&destFolderPath={destFolderPath}&sizeBytes={ sizeBytes }&fileOverwrite=true&output=json
* https://{uploadHost}/Upload.ashx?uploadToken={uploadToken}&destFolderPath={destFolderPath}&metadata={metadata} REQUIRED: uploadToken
*
* REQUIRED: destFolderPath - The destination path of the files being uploaded.
*
* REQUIRED: metadata - The sha1 metadata to be associated with the uploaded file.
*/
public String putFile( String fileName, String destPath, Map<String, String> metadata, InputStream data, String sessionToken,
final int contentLengthInBytes ) throws RuleException, SystemException, UnexpectedException, IOException {
if( isNullOrEmpty( fileName ) ) {
throw new RuleException( ResponseCategory.InvalidInputPutFileFileName.code, "ERROR: Cannot put file as fileName is not valid" );
}
if( isNullOrEmpty( destPath ) ) {
throw new RuleException( ResponseCategory.InvalidInputPutFileDestPath.code, "ERROR: Cannot put file as destPath is not valid" );
}
if( isNullOrEmpty( sessionToken ) ) {
throw new RuleException( ResponseCategory.InvalidInputPutFileSessionToken.code,
"ERROR: Cannot put file as sessionToken is not valid" );
}
if( data == null ) {
throw new RuleException( ResponseCategory.InvalidInputPutFileData.code, "ERROR: Cannot get put file as data is not valid (null)" );
}
// Acquire the uploadHost and uploadToken - Critical call uses https
String uploadHost = null;
String uploadToken = null;
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme( "https" ).setHost( this.apiHostname ).setPath( GET_UPLOAD_TOKEN ).setParameter( "sessionToken", sessionToken )
.setParameter( "destFolderPath", destPath ).setParameter( "sizeBytes", "" + contentLengthInBytes )
.setParameter( "fileOverwrite", "true" ).setParameter( "output", "json" );
String response = executeHttp( uriBuilder ); // Use a private helper method to get the response as a String (JSON)
try {
JSONObject JSONresponse = new JSONObject( response );
assertValidNirvanixResponse( JSONresponse.getString( "ResponseCode" ) );
JSONObject getStorageNode = JSONresponse.getJSONObject( "GetStorageNode" );
uploadHost = getStorageNode.getString( "UploadHost" );
uploadToken = getStorageNode.getString( "UploadToken" );
} catch( JSONException e ) {
throw new UnexpectedException( ResponseCategory.JSONSyntaxExceptionPutFile.code
+ ",ERROR: Put file encountered a JSON Exception " + e.getMessage() );
}
logger.debug( "uploadHost = " + uploadHost + " and uploadToken = " + uploadToken );
// Prepare metadata
StringBuilder metadataBuilder = new StringBuilder();
if( metadata != null ) {
for( Map.Entry<String, String> entry : metadata.entrySet() ) {
if( metadataBuilder.length() > 0 ) {
metadataBuilder.append( "," );
}
metadataBuilder.append( entry.getKey() + ":" + entry.getValue() );
}
}
// Prepare the URL to upload a file, note: cannot receive a JSON response so must parse the XML
uriBuilder = new URIBuilder();
uriBuilder.setScheme( this.clientPreferedDataTransferProtocol ).setHost( uploadHost ).setPath( UPLOAD )
.setParameter( "uploadToken", uploadToken ).setParameter( "destFolderPath", destPath )
.setParameter( "metadata", metadataBuilder.toString() );
URI uri;
try {
uri = uriBuilder.build();
} catch( URISyntaxException e ) {
throw new UnexpectedException( ResponseCategory.URISyntaxException.code + ",ERROR: Put file encountered a URI Syntax Exception "
+ e.getMessage() );
}
InputStreamBodyBuffered bufferedBody = new InputStreamBodyBuffered( data, "binary/octet-stream", fileName );
bufferedBody.setBufferSizeInBytes( 20480 ); // 2MB maximum buffer per thread, balance between performance and many threads
bufferedBody.setContentLengthInBytes( contentLengthInBytes );
MultipartEntity multipartEntity = new MultipartEntity();
multipartEntity.addPart( fileName, bufferedBody );
HttpPost httpPost = new HttpPost( uri );
httpPost.setEntity( multipartEntity );
String xmlResponse = executeHttpPost( httpPost ); // Use a private helper method to get the response as XML
logger.debug( "NirvanixResponse " + xmlResponse );
parseNirvanixXMLResponse( xmlResponse );
if( data != null ) {
data.close();
}
return destPath + "/" + fileName;
}
private void parseNirvanixXMLResponse( String xmlResponse ) throws RuleException {
if( !xmlResponse.contains( "<ResponseCode>0</ResponseCode>" ) ) {
throw new RuleException( ResponseCategory.ErrorResponsePutFile.code,
"ERROR: Put file received 'put unsuccessful' response from Nirvanix:\n" + xmlResponse );
}
}
public Map<String, String> getMetadata( String fileId, String sessionToken ) throws RuleException, SystemException,
UnexpectedException, IOException {
if( isNullOrEmpty( fileId ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetMetadataFileId.code, "ERROR: Cannot get metadata as fileId is not valid" );
}
if( isNullOrEmpty( sessionToken ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetMetadataSessionToken.code,
"ERROR: Cannot get metadata as sessionToken is not valid" );
}
HashMap<String, String> metadataMap = new HashMap<String, String>();
// Build the URI with the current session token to retrieve the metadata of the fileId = full path and filename - Critical call uses https
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme( "https" ).setHost( this.apiHostname ).setPath( GET_METADATA ).setParameter( "sessionToken", sessionToken )
.setParameter( "path", fileId ).setParameter( "output", "json" );
String response = executeHttp( uriBuilder ); // Use a private helper method to get the response as a String (JSON)
try {
JSONObject responseJSON = new JSONObject( response );
assertValidNirvanixResponse( responseJSON.getString( "ResponseCode" ) );
JSONArray metadataJSONArray = responseJSON.getJSONArray( "Metadata" );
for( int i = 0; i < metadataJSONArray.length(); i++ ) {
JSONObject temp = metadataJSONArray.getJSONObject( i );
metadataMap.put( temp.getString( "Type" ), temp.getString( "Value" ) );
}
} catch( JSONException e ) {
throw new UnexpectedException( ResponseCategory.JSONSyntaxExceptionGetMetadata.code
+ ",ERROR: Get metadata encountered a JSON Exception " + e.getMessage() );
}
return metadataMap;
}
public String getMetadata( String fileId, String key, String sessionToken ) throws RuleException, SystemException, UnexpectedException,
IOException {
if( isNullOrEmpty( fileId ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetMetadataFileId.code, "ERROR: Cannot get metadata as fileId is not valid" );
}
if( isNullOrEmpty( sessionToken ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetMetadataSessionToken.code,
"ERROR: Cannot get metadata as sessionToken is not valid" );
}
if( isNullOrEmpty( key ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetMetadataKey.code, "ERROR: Cannot get metadata as key is not valid" );
}
String value = null;
// Build the URI with the current session token to retrieve the metadata of the fileId = full path and filename - Critical call uses https
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme( "https" ).setHost( this.apiHostname ).setPath( GET_METADATA ).setParameter( "sessionToken", sessionToken )
.setParameter( "path", fileId ).setParameter( "output", "json" );
String response = executeHttp( uriBuilder ); // Use a private helper method to get the response as a String (JSON)
try {
JSONObject responseJSON = new JSONObject( response );
assertValidNirvanixResponse( responseJSON.getString( "ResponseCode" ) );
JSONArray metadataJSONArray = responseJSON.getJSONArray( "Metadata" );
for( int i = 0; i < metadataJSONArray.length(); i++ ) {
JSONObject metadataKeyValuePair = metadataJSONArray.getJSONObject( i );
if( metadataKeyValuePair.getString( "Type" ).equals( key ) ) {
value = metadataKeyValuePair.getString( "Value" );
}
}
} catch( JSONException e ) {
throw new UnexpectedException( ResponseCategory.JSONSyntaxExceptionGetMetadata.code
+ ",ERROR: Get metadata encountered a JSON Exception " + e.getMessage() );
}
if( value == null ) {
throw new RuleException( ResponseCategory.ErrorResponseGetMetadata.code, "ERROR: no value found for key = " + key );
}
return value;
}
public InputStream getFile( String fileId, String sessionToken ) throws RuleException, SystemException, UnexpectedException,
IOException {
if( isNullOrEmpty( fileId ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetFileFileId.code, "ERROR: Cannot get file as fileId is not valid" );
}
if( isNullOrEmpty( sessionToken ) ) {
throw new RuleException( ResponseCategory.InvalidInputGetFileSessionToken.code,
"ERROR: Cannot get file as sessionToken is not valid" );
}
URI downloadURI = getDownloadURI( fileId, sessionToken ); // Use a helper method to get the download URL
return executeHttpAndGetResponseAsStream( downloadURI );
}
public void delete( String fileId, String sessionToken ) throws RuleException, SystemException, UnexpectedException, IOException {
if( isNullOrEmpty( fileId ) ) {
throw new RuleException( ResponseCategory.InvalidInputDeleteFileId.code, "ERROR: Cannot delete as fileId is not valid" );
}
if( isNullOrEmpty( sessionToken ) ) {
throw new RuleException( ResponseCategory.InvalidInputDeleteSessionToken.code,
"ERROR: Cannot delete as sessionToken is not valid" );
}
// Call nirvanix delete api using http get - Critical call uses https
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme( "https" ).setHost( this.apiHostname ).setPath( DELETE ).setParameter( "sessionToken", sessionToken )
.setParameter( "filePath", fileId ).setParameter( "output", "json" );
String response = executeHttp( uriBuilder ); // Use a private helper method to get the response as a String (JSON)
try {
JSONObject responseJSON = new JSONObject( response );
assertValidNirvanixResponse( responseJSON.getString( "ResponseCode" ) );
} catch( JSONException e ) {
throw new UnexpectedException( ResponseCategory.JSONSyntaxExceptionDelete.code + ",ERROR: Delete encountered a JSON Exception "
+ e.getMessage() );
}
}
/* Nirvanix REST parameters for GetOptimalUrls (returns download web link, expire as given) https://{apiHostName}/ws/IMFS/GetOptimalUrls. ashx?sessionToken={sessionToken}&={filePath}&expiration={expirationInSeconds}&output=json REQUIRED: sessionToken REQUIRED: filePath (must be a valid path string to a files) REQUIRED: expiration - DOWNLOAD_TOKEN_EXPIRATION_IN_SECONDS */
protected URI getDownloadURI( String filePath, String sessionToken ) throws SystemException, UnexpectedException, IOException {
// Execute an Http Get to receive and extract from a JSON Array the download url - Critical call uses https
URI downloadURI;
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme( "https" ).setHost( this.apiHostname ).setPath( GET_DOWNLOAD_TOKEN )
.setParameter( "sessionToken", sessionToken ).setParameter( "filePath", filePath )
.setParameter( "expiration", "" + DOWNLOAD_TOKEN_EXPIRATION_IN_SECONDS ).setParameter( "output", "json" );
try {
JSONObject responseJSON = new JSONObject( executeHttp( uriBuilder ) );
assertValidNirvanixResponse( responseJSON.getString( "ResponseCode" ) );
JSONArray downloadJSONArray = responseJSON.getJSONArray( "Download" );
String downloadURL = downloadJSONArray.getJSONObject( 0 ).getString( "DownloadURL" );
logger.debug( "downloadURL = " + downloadURL );
try {
uriBuilder = new URIBuilder( downloadURL );
uriBuilder.setScheme( this.clientPreferedDataTransferProtocol );
downloadURI = uriBuilder.build();
} catch( URISyntaxException e ) {
throw new UnexpectedException( ResponseCategory.URISyntaxException.code
+ ",ERROR: get download url encountered a URI Syntax Exception " + e.getMessage() );
}
} catch( JSONException e ) {
throw new UnexpectedException( ResponseCategory.JSONSyntaxExceptionGetDownloadUrl.code
+ ",ERROR: Get download URL encountered a JSON Exception " + e.getMessage() );
}
return downloadURI;
}
// Returns null if the response entity does not have isStreaming set to true
protected InputStream executeHttpAndGetResponseAsStream( URI uri ) throws IOException {
InputStream inputstream = null;
HttpEntity entity = null;
HttpGet httpget = new HttpGet( uri );
logger.debug( "getURIAsStream = " + uri.toString() );
HttpResponse response = NirvanixStorageConnector.httpclient.execute( httpget );
logger.debug( "HTTPResponse = " + response.getStatusLine().toString() );
entity = response.getEntity();
if( entity != null ) {
if( entity.isStreaming() ) {
inputstream = entity.getContent();
}
}
return inputstream;
}
protected String executeHttp( URIBuilder uriBuilder ) throws IOException, UnexpectedException {
URI uri;
try {
uri = uriBuilder.build();
} catch( URISyntaxException e ) {
throw new UnexpectedException( ResponseCategory.URISyntaxException + ",URISyntaxException=" + e.getMessage() );
}
HttpGet httpget = new HttpGet( uri );
logger.debug( "httpGet = " + uri.toString() );
HttpResponse response = NirvanixStorageConnector.httpclient.execute( httpget );
logger.debug( "HTTPResponse = " + response.getStatusLine().toString() );
String nirvanixResponse = EntityUtils.toString( response.getEntity(), "US-ASCII" );
logger.debug( "nirvanixResponse = " + nirvanixResponse );
return nirvanixResponse;
}
protected String executeHttpPost( HttpUriRequest method ) throws IOException {
logger.debug( "executeMultiPartHttpPost = " + method.getURI().toString() );
HttpResponse response = NirvanixStorageConnector.httpclient.execute( method );
logger.debug( "HTTPResponse = " + response.getStatusLine().toString() );
String nirvanixResponse = EntityUtils.toString( response.getEntity(), "US-ASCII" );
logger.debug( "nirvanixResponse = " + nirvanixResponse );
return nirvanixResponse;
}
private boolean isNullOrEmpty( String name ) {
if( name == null ) {
return true;
}
return name.isEmpty();
}
// ERROR HANDLING
class SystemException extends UnexpectedException {
private static final long serialVersionUID = 4665361228364824402L;
private int code;
private String message;
public SystemException( String s ) {
super( s );
}
public SystemException( String s, Exception e ) {
super( s, e );
}
public SystemException( int code, String s ) {
super( s );
this.code = code;
this.message = s;
}
public SystemException( int code, String s, Exception e ) {
super( s, e );
this.code = code;
this.message = s;
}
public int getCode() {
return code;
}
public String getCodeMessage() {
return message;
}
}
class RuleException extends UnexpectedException {
private static final long serialVersionUID = -6136649548128196831L;
private int code;
private String message;
public RuleException( String s ) {
super( s );
}
public RuleException( String s, Exception e ) {
super( s, e );
}
public RuleException( int code, String s ) {
super( s );
this.code = code;
this.message = s;
}
public RuleException( int code, String s, Exception e ) {
super( s, e );
this.code = code;
this.message = s;
}
public int getCode() {
return code;
}
public String getCodeMessage() {
return message;
}
}
private void assertValidNirvanixResponse( String responseCodeString ) throws IOException {
int responseCode = -1;
try {
responseCode = Integer.parseInt( responseCodeString );
} catch( NumberFormatException e ) {
throw new UnexpectedException( "ERROR: response code from Nirvanix was not a number " + e.getMessage() );
}
NirvanixResponseCode error = NirvanixResponseCode.getResponseCodeByID( responseCode );
switch( error ) {
case OK: // placed here for logical organization but for performance could be moved out
break;
case InvalidAccessToken:
throw new RuleException( ResponseCategory.InvalidSessionToken.code, "ERROR: Nirvanix access token invalid (nirvanixcode="
+ responseCodeString + ")" );
case ExpiredAccessToken: // This should be handled by the class by resending credentials to reacquire a session
throw new RuleException( ResponseCategory.InvalidSessionToken.code, "ERROR: Nirvanix access token expired (nirvanixcode="
+ responseCodeString + ")" );
case InvalidSessionToken: // This should be handled by the class by resending credentials to reacquire a session
throw new RuleException( ResponseCategory.InvalidSessionToken.code, "ERROR: Nirvanix session token invalid (nirvanixcode="
+ responseCodeString + ")" );
case SessionNotFound: // Session ended with either a logout or expiration
throw new RuleException( ResponseCategory.InvalidSessionToken.code, "ERROR: Nirvanix session not found (nirvanixcode="
+ responseCodeString + ")" );
case MissingRequiredParameter: // Would only occur when the session token is null, should try to reacquire a session
throw new RuleException( ResponseCategory.InvalidSessionToken.code,
"ERROR: Nirvanix missing an required parameter = sessionToken (nirvanixcode=" + responseCodeString + ")" );
case LoginFailed:
throw new RuleException( ResponseCategory.InvalidSessionToken.code, "ERROR: Nirvanix login failed(nirvanixcode="
+ responseCodeString + ")" );
case PathTooLong:
throw new RuleException( ResponseCategory.InvalidInput.code,
"ERROR: length of a relative path exceeds the maximum length of 512 characters (nirvanixcode=" + responseCodeString
+ ")" );
case FileFolderNameTooLong:
throw new RuleException( ResponseCategory.InvalidInput.code,
"ERROR: file or folder name exceeds the maximum length of 256 characters (nirvanixcode=" + responseCodeString + ")" );
case InvalidPathCharacter:
throw new RuleException( ResponseCategory.InvalidInput.code, "ERROR: invalid character in path (nirvanixcode="
+ responseCodeString + ")" );
case AlreadyExists: // only applies if Nirvanix Storage Pool is configured with fileOverwrite = false
throw new RuleException( ResponseCategory.InvalidInput.code, "ERROR: object already exists (nirvanixcode="
+ responseCodeString + ")" );
case InvalidPath:
throw new RuleException( ResponseCategory.InvalidPath.code, "ERROR: folder or file path does not exist (nirvanixcode="
+ responseCodeString + ")" );
case InvalidUploadRequest:
throw new RuleException( ResponseCategory.InvalidInput.code, "ERROR: invalid upload request (nirvanixcode="
+ responseCodeString + ")" );
case RestrictedIPAddress: // Must be fixed by an external source , may be a network configuration or Nirvanix security issue
throw new SystemException( ResponseCategory.InvalidAccountConfiguration.code,
"ERROR: restricted ip address requires contacting Nirvanix Support (nirvanixcode=" + responseCodeString + ")" );
case AccessDenied:
throw new SystemException( ResponseCategory.InvalidAccountConfiguration.code,
"ERROR: access denied requires contacting Nirvanix Support (nirvanixcode=" + responseCodeString + ")" );
case StorageLimitExceeded:
throw new SystemException( ResponseCategory.InvalidAccountConfiguration.code,
"ERROR: Nirvanix storage limit exceeded requires contacting Nirvanix Support (nirvanixcode=" + responseCodeString
+ ")" );
case NoRouteToSdn: // if configured to use excludeNode parameter this can result in no suitable storage node to use
throw new SystemException( ResponseCategory.InvalidAccountConfiguration.code,
"ERROR: no route to suitable Nirvanix Storage Delivery Network (Node) (nirvanixcode=" + responseCodeString + ")" );
case UploadAborted:
throw new IOException( ResponseCategory.ErrorResponsePutFile.code
+ ",ERROR: put file received an aborted upload response from Nirvanix (nirvanixcode=" + responseCodeString + ")" );
default:
throw new UnexpectedException( "UnexpectedException, nirvanixcode=" + responseCode );
}
}
private enum NirvanixResponseCode {
Unknown( 2147483647 ),
OK( 0 ),
MissingRequiredParameter( 100 ),
InvalidParameter( 101 ),
UnsupportedOperation( 160 ),
ParameterOutOfAcceptedRange( 50103 ),
InvalidPayment( 55001 ),
CreditCardChargeFailed( 55100 ),
CreateAccountFailed( 65001 ),
CreateAccountContactFailed( 65002 ),
InvalidAppKey( 65004 ),
InvalidAccountType( 65005 ),
DuplicateUserNameUnderAppKey( 65006 ),
DuplicateAppName( 65007 ),
PageSizeExceedsLimit( 65008 ),
DeletedAccount( 65009 ),
InvalidStatus( 65010 ),
InvalidSecurityResponse( 65011 ),
InvalidUserNameOrPassword( 65012 ),
DuplicateMasterAccountUserName( 65016 ),
PageNumberExceeded( 65017 ),
InvalidContactParameter( 65101 ),
AppNameNotFound( 65102 ),
UserNameNotFoundUnderAppKey( 65103 ),
UserNameNotFound( 65104 ),
FolderNotFound( 70001 ),
FileNotFound( 70002 ),
PathNotFound( 70003 ),
AlreadyExists( 70004 ),
InvalidPath( 70005 ),
DownloadPathNotFound( 70006 ),
MetadataDoesNotExist( 70007 ),
FolderAlreadyExists( 70008 ),
PathTooLong( 70009 ),
FileFolderNameTooLong( 70010 ),
ItemAlreadyShared( 70012 ),
PathNotShared( 70013 ),
NullOrEmptyPath( 70101 ),
InvalidPathCharacter( 70102 ),
InvalidAbsolutePath( 70103 ),
InvalidRelativePath( 70104 ),
FileIntegrityError( 70106 ),
InvalidMetadata( 70107 ),
RangeNotSatisfiable( 70108 ),
PathTooShort( 70109 ),
FileOffline( 70110 ),
InvalidImageDimensions( 70111 ),
InvalidRotateFlipType( 70112 ),
InvalidSearchItem( 70113 ),
InvalidFileFolderNameCharacter( 70114 ),
TagNotFound( 70115 ),
InvalidImage( 70116 ),
InvalidDateRange( 70117 ),
InvalidSizeRange( 70118 ),
InvalidTagCharacter( 70119 ),
SideloadError( 70120 ),
InvalidUploadRequest( 70121 ),
UploadAborted( 70122 ),
InvalidImageFormat( 70123 ),
InvalidTranscodeOutput( 70124 ),
InvalidFileFormat( 70125 ),
TranscodeFailed( 70126 ),
InvalidStartTimeOffset( 70127 ),
VideoFrameExtractionFailed( 70128 ),
MD5DoesNotMatch( 70129 ),
InvalidMD5SearchTerm( 70130 ),
InvalidIngestRequest( 70131 ),
BadIngestionPhysicalPath( 70132 ),
IngestionThrottled( 70133 ),
TranscodingPresetNotFound( 70134 ),
InvalidFileAccess( 70136 ),
MD5ServiceUnavailable( 70137 ),
LogicalFileIDUpdate( 70204 ),
NoRouteToSdn( 70205 ),
LoginFailed( 80001 ),
AccessDenied( 80003 ),
InvalidMasterAccountID( 80004 ),
InvalidBillableAccountID( 80005 ),
SessionNotFound( 80006 ),
AccountExpired( 80007 ),
OutOfBytes( 80015 ),
OutOfBytesNonOwner( 80016 ),
InvalidIPAddress( 80018 ),
DownloadFileSizeLimitExceded( 80019 ),
UploadBandwidthLimitExceeded( 80020 ),
StorageLimitExceeded( 80021 ),
LimitAlreadyExceeded( 80022 ),
InvalidAccessToken( 80023 ),
InvalidSessionToken( 80101 ),
ExpiredAccessToken( 80102 ),
InvalidDownloadToken( 80103 ),
RestrictedIPAddress( 80104 ),
StorageNotAvailable( 85001 ),
ServerNotFound( 85003 ),
Configuration( 90001 ),
SSLRequired( 90002 ),
ServerError( 100001 ),
HttpResponseError( 2000000 ),
NewUploadTokenRequired( 2000000 );
private int code;
private NirvanixResponseCode( int c ) {
this.code = c;
}
public int getResponseCode() {
return this.code;
}
public static NirvanixResponseCode getResponseCodeByID( int responseCodeID ) {
NirvanixResponseCode[] allResponseCodes = values();
for( int idx = 0; idx < allResponseCodes.length; idx++ ) {
if( allResponseCodes[idx].getResponseCode() == responseCodeID ) {
return allResponseCodes[idx];
}
}
return Unknown;
}
}
public enum ResponseCategory {
InvalidInputConstructorApiHostname( 101 ),
InvalidInputConstructorDataTransferProtocol( 102 ),
InvalidInputGetSessionAppKey( 201 ),
InvalidInputGetSessionUsername( 202 ),
InvalidInputGetSessionPassword( 203 ),
JSONSyntaxExceptionGetSession( 205 ),
InvalidInputPutFileFileName( 301 ),
InvalidInputPutFileDestPath( 302 ),
InvalidInputPutFileSessionToken( 303 ),
InvalidInputPutFileData( 304 ),
JSONSyntaxExceptionPutFile( 305 ),
ErrorResponsePutFile( 306 ),
InvalidInputGetFileFileId( 401 ),
InvalidInputGetFileSessionToken( 402 ),
JSONSyntaxExceptionGetDownloadUrl( 405 ),
InvalidInputGetMetadataFileId( 501 ),
InvalidInputGetMetadataSessionToken( 502 ),
InvalidInputGetMetadataKey( 503 ),
JSONSyntaxExceptionGetMetadata( 505 ),
ErrorResponseGetMetadata( 506 ),
InvalidInputDeleteFileId( 601 ),
InvalidInputDeleteSessionToken( 602 ),
JSONSyntaxExceptionDelete( 605 ),
InvalidInput( 700 ),
InvalidAccountConfiguration( 701 ),
InvalidPath( 702 ),
InvalidSessionToken( 800 ),
URISyntaxException( 900 );
int code;
private ResponseCategory( int c ) {
this.code = c;
}
public int getCode() {
return code;
}
}
class InputStreamBodyBuffered extends InputStreamBody {
private InputStream bufferedInputStream = null;
private int contentLengthInBytes;
private int bufferSizeInBytes = 10240; // defaults to 1MB
public InputStreamBodyBuffered( final InputStream in, final String mimeType, final String filename ) {
super( in, mimeType, filename );
bufferedInputStream = super.getInputStream();
}
void setContentLengthInBytes( int contentLengthInBytes ) {
this.contentLengthInBytes = contentLengthInBytes;
}
void setBufferSizeInBytes( int bufferSizeInBytes ) {
if( bufferSizeInBytes < 1 ) {
throw new IllegalArgumentException( "bufferSizeInBytes must be greater than 0" );
}
this.bufferSizeInBytes = bufferSizeInBytes;
}
@Override
public void writeTo( final OutputStream out ) throws IOException {
if( out == null ) {
throw new IllegalArgumentException( "Output stream may not be null" );
}
try {
byte[] tmp = new byte[bufferSizeInBytes];
int l;
while( (l = bufferedInputStream.read( tmp )) != -1 ) {
out.write( tmp, 0, l );
}
out.flush();
} finally {
if( bufferedInputStream != null ) {
bufferedInputStream.close();
}
}
}
@Override
public long getContentLength() {
return contentLengthInBytes; // otherwise always returns -1
}
} // end inner class
} // end class