john pfeiffer
  • Home
  • Categories
  • Tags
  • Archives

NirvanixStorageConnector

//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

  • « NirvanixStorageConnectorTest
  • array to ArrayList Pairs »

Published

Dec 5, 2012

Category

java-classes

~2602 words

Tags

  • classes 92
  • java 252
  • nirvanixstorageconnector 1