Java tutorial
// // Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // A copy of the License is located at // // http://aws.amazon.com/apache2.0 // // or in the "license" file accompanying this file. This file 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 com.amazonaws.reactnative.s3; import android.os.Environment; import android.support.annotation.Nullable; import android.util.Log; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.mobileconnectors.s3.transferutility.TransferListener; import com.amazonaws.mobileconnectors.s3.transferutility.TransferObserver; import com.amazonaws.mobileconnectors.s3.transferutility.TransferState; import com.amazonaws.mobileconnectors.s3.transferutility.TransferType; import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility; import com.amazonaws.reactnative.core.AWSRNClientConfiguration; import com.amazonaws.reactnative.core.AWSRNCognitoCredentials; import com.amazonaws.regions.Region; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; import java.io.File; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class AWSRNS3TransferUtility extends ReactContextBaseJavaModule { private TransferUtility transferUtility; private static final Map<String, Map<String, Object>> requestMap = new ConcurrentHashMap<>(); private static final Map<Integer, String> transferIDMap = new ConcurrentHashMap<>(); private static final String REQUESTID = "requestid"; private static final String TRANSFERID = "transferid"; private static final String BUCKET = "bucket"; private static final String KEY = "key"; private static final String PATH = "path"; private static final String SUBSCRIBE = "subscribe"; private static final String COMPLETIONHANDLER = "completionhandler"; private static final String TYPE = "type"; private static final String UPLOAD = "upload"; private static final String DOWNLOAD = "download"; private static final String REQUEST = "request"; private static final String CONFIG = "config"; private static final String OPTION = "option"; private static final String PAUSE = "pause"; private static final String RESUME = "resume"; private static final String CANCEL = "cancel"; private static final String ALL = "all"; private static final String ERROR = "error"; private static final String REGION = "region"; private static final String COMPLETEDUNITCOUNT = "completedunitcount"; private static final String TOTALUNITCOUNT = "totalunitcount"; private static final String FRACTIONCOMPLETED = "fractioncompleted"; private static final String DESCRIPTION = "description"; private static final String CODE = "code"; private static final String LOCATION = "location"; public AWSRNS3TransferUtility(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { return "AWSRNS3TransferUtility"; } @ReactMethod public void initWithOptions(final ReadableMap options) { if (!options.hasKey(REGION)) { throw new IllegalArgumentException("region not supplied"); } final AWSRNCognitoCredentials credentials = this.getReactApplicationContext() .getNativeModule(AWSRNCognitoCredentials.class); if (credentials.getCredentialsProvider() == null) { throw new IllegalArgumentException("AWSCognitoCredentials is not initialized"); } final AmazonS3 s3 = new AmazonS3Client(credentials.getCredentialsProvider(), new AWSRNClientConfiguration().withUserAgent("AWSS3TransferUtility")); s3.setRegion(Region.getRegion(Regions.fromName(options.getString(REGION)))); transferUtility = new TransferUtility(s3, getReactApplicationContext()); } @ReactMethod public void createDownloadRequest(final ReadableMap options, final Callback callback) { if (requestMap == null) { callback.invoke("Error: AWSS3TransferUtility is not initialized", null); return; } final String[] params = { BUCKET, KEY, PATH, SUBSCRIBE, COMPLETIONHANDLER }; for (int i = 0; i < params.length; i++) { if (!options.hasKey(params[i])) { callback.invoke(params[i] + " is not supplied", null); return; } } final Map<String, Object> map = new ConcurrentHashMap<>(); map.put(BUCKET, options.getString(BUCKET)); map.put(KEY, options.getString(KEY)); map.put(PATH, Environment.getExternalStorageDirectory() + options.getString(PATH)); map.put(TYPE, DOWNLOAD); map.put(SUBSCRIBE, options.getBoolean(SUBSCRIBE)); map.put(COMPLETIONHANDLER, options.getBoolean(COMPLETIONHANDLER)); final UUID uuid = UUID.randomUUID(); requestMap.put(uuid.toString(), map); callback.invoke(null, uuid.toString()); } @ReactMethod public void download(final ReadableMap options, final Promise promise) { if (!options.hasKey(REQUESTID)) { throw new IllegalArgumentException("requestid is not supplied"); } final String requestID = options.getString(REQUESTID); final Map<String, Object> map = requestMap.get(requestID); if (map == null) { throw new IllegalArgumentException("requestid is invalid"); } final TransferObserver observer; try { observer = transferUtility.download((String) map.get(BUCKET), (String) map.get(KEY), new File((String) map.get(PATH))); } catch (final AmazonServiceException e) { promise.reject(e.getErrorCode(), e.getErrorMessage(), e); return; } catch (final AmazonClientException e) { promise.reject("", e.getMessage(), e); return; } transferIDMap.put(observer.getId(), requestID); map.put(TRANSFERID, observer.getId()); if ((Boolean) map.get(SUBSCRIBE)) { this.subscribe(observer); } promise.resolve("success"); } @ReactMethod public void createUploadRequest(final ReadableMap options, final Callback callback) { if (requestMap == null) { callback.invoke("Error: AWSS3TransferUtility is not initialized", null); return; } final String[] params = { BUCKET, KEY, PATH, SUBSCRIBE, COMPLETIONHANDLER }; for (int i = 0; i < params.length; i++) { if (!options.hasKey(params[i])) { callback.invoke(params[i] + " is not supplied", null); return; } } final Map<String, Object> map = new ConcurrentHashMap<>(); map.put(BUCKET, options.getString(BUCKET)); map.put(KEY, options.getString(KEY)); map.put(PATH, options.getString(PATH)); map.put(SUBSCRIBE, options.getBoolean(SUBSCRIBE)); map.put(COMPLETIONHANDLER, options.getBoolean(COMPLETIONHANDLER)); map.put(TYPE, UPLOAD); final UUID uuid = UUID.randomUUID(); requestMap.put(uuid.toString(), map); callback.invoke(null, uuid.toString()); } @ReactMethod public void upload(final ReadableMap options, final Promise promise) { if (!options.hasKey(REQUESTID)) { throw new IllegalArgumentException("requestid is not supplied"); } final String requestID = options.getString(REQUESTID); final Map<String, Object> map = requestMap.get(requestID); if (map == null) { throw new IllegalArgumentException("requestid is invalid"); } final TransferObserver observer; try { observer = transferUtility.upload((String) map.get(BUCKET), (String) map.get(KEY), new File((String) map.get(PATH))); } catch (final AmazonServiceException e) { promise.reject(e.getErrorCode(), e.getErrorMessage(), e); return; } catch (final AmazonClientException e) { promise.reject("", e.getMessage(), e); return; } transferIDMap.put(observer.getId(), requestID); map.put(TRANSFERID, observer.getId()); if ((Boolean) map.get(SUBSCRIBE)) { this.subscribe(observer); } promise.resolve("success"); } @ReactMethod public void editRequest(final ReadableMap options) { if (!options.hasKey(CONFIG)) { throw new IllegalArgumentException("config not supplied"); } final String config = options.getString(CONFIG); String option = null; if (options.hasKey(OPTION)) { option = options.getString(OPTION); } String request = null; if (options.hasKey(REQUEST)) { request = options.getString(REQUEST); } if (option == null && request == null) { throw new IllegalArgumentException("request and option not supplied. Please supply one"); } if (option != null && request != null) { throw new IllegalArgumentException("request and option are both supplied. Please only supply one"); } if (config.contentEquals(PAUSE)) { this.pause(request, option); } else if (config.contentEquals(RESUME)) { this.resume(request, option); } else if (config.contentEquals(CANCEL)) { this.cancel(request, option); } } public void pause(final String request, final String option) { if (request != null) { final Map<String, Object> req = requestMap.get(request); if (req == null) { Log.w(this.getClass().toString(), "Pause: request is invalid"); return; } final int id = (int) req.get(TRANSFERID); try { transferUtility.pause(id); } catch (final AmazonClientException e) { throw e; } } else { if (option.contentEquals(ALL)) { try { transferUtility.pauseAllWithType(TransferType.ANY); } catch (final AmazonClientException e) { throw e; } } else if (option.contentEquals(UPLOAD)) { try { transferUtility.pauseAllWithType(TransferType.UPLOAD); } catch (final AmazonClientException e) { throw e; } } else if (option.contentEquals(DOWNLOAD)) { try { transferUtility.pauseAllWithType(TransferType.DOWNLOAD); } catch (final AmazonClientException e) { throw e; } } } } public void resume(final String request, final String option) { if (request != null) { Map<String, Object> req = requestMap.get(request); if (req == null) { Log.w(this.getClass().toString(), "Resume: request is invalid"); return; } int id = (int) req.get(TRANSFERID); try { transferUtility.resume(id); } catch (final AmazonClientException e) { throw e; } } else { if (option.contentEquals(ALL)) { List<TransferObserver> list = null; try { list = transferUtility.getTransfersWithTypeAndState(TransferType.ANY, TransferState.PAUSED); } catch (final AmazonClientException e) { throw e; } for (TransferObserver observer : list) { try { transferUtility.resume(observer.getId()); } catch (final AmazonClientException e) { throw e; } } } else if (option.contentEquals(UPLOAD)) { List<TransferObserver> list = null; try { list = transferUtility.getTransfersWithTypeAndState(TransferType.UPLOAD, TransferState.PAUSED); } catch (final AmazonClientException e) { throw e; } for (TransferObserver observer : list) { try { transferUtility.resume(observer.getId()); } catch (final AmazonClientException e) { throw e; } } } else if (option.contentEquals(DOWNLOAD)) { List<TransferObserver> list = null; try { list = transferUtility.getTransfersWithTypeAndState(TransferType.DOWNLOAD, TransferState.PAUSED); } catch (final AmazonClientException e) { throw e; } for (TransferObserver observer : list) { try { transferUtility.resume(observer.getId()); } catch (final AmazonClientException e) { throw e; } } } } } public void cancel(final String request, final String option) { if (request != null) { Map<String, Object> req = requestMap.get(request); if (req == null) { Log.w(this.getClass().toString(), "Cancel: request is invalid"); return; } int transferid = (int) req.get(TRANSFERID); try { transferUtility.cancel(transferid); } catch (final AmazonClientException e) { throw e; } this.removeTransferFromMap(request, transferid); } else { if (option.contentEquals(ALL)) { try { transferUtility.cancelAllWithType(TransferType.ANY); } catch (final AmazonClientException e) { throw e; } requestMap.clear(); } else if (option.contentEquals(UPLOAD)) { try { transferUtility.cancelAllWithType(TransferType.UPLOAD); } catch (final AmazonClientException e) { throw e; } removeTransfers(UPLOAD); } else if (option.contentEquals(DOWNLOAD)) { try { transferUtility.cancelAllWithType(TransferType.DOWNLOAD); } catch (final AmazonClientException e) { throw e; } removeTransfers(DOWNLOAD); } } } private void removeTransfers(final String type) { final Iterator it = requestMap.entrySet().iterator(); while (it.hasNext()) { final Map.Entry pair = (Map.Entry) it.next(); if (pair == null) { return; } final Map<String, Object> map = (Map<String, Object>) pair.getValue(); final String reqType = (String) map.get(TYPE); if (reqType.contentEquals(type)) { this.removeTransferFromMap((String) pair.getKey(), (int) map.get(TRANSFERID)); } } } private void subscribe(TransferObserver observer) { observer.setTransferListener(new TransferListener() { @Override public void onStateChanged(final int id, final TransferState state) { final WritableMap map = Arguments.createMap(); final String uuid = transferIDMap.get(id); final Map<String, Object> req = requestMap.get(uuid); if (!(boolean) req.get(COMPLETIONHANDLER)) { return; } map.putString(REQUESTID, uuid); if (state == TransferState.CANCELED) { map.putString(ERROR, "canceled"); } else if (state == TransferState.FAILED) { map.putString(ERROR, "failed"); } else if (state == TransferState.COMPLETED) { final WritableMap request = Arguments.createMap(); TransferObserver observer = null; try { observer = transferUtility.getTransferById(id); } catch (final AmazonClientException e) { throw e; } request.putString(BUCKET, observer.getBucket()); request.putString(KEY, observer.getKey()); request.putString(LOCATION, observer.getAbsoluteFilePath()); map.putMap(REQUEST, request); removeTransferFromMap(uuid, id); } if ((state.equals(TransferState.CANCELED) || state.equals(TransferState.FAILED) || state.equals(TransferState.COMPLETED)) && (map.hasKey(ERROR) || map.hasKey(REQUEST))) { sendEvent(getReactApplicationContext(), "CompletionHandlerEvent", map); } } @Override public void onProgressChanged(final int id, final long bytesCurrent, final long bytesTotal) { final WritableMap map = Arguments.createMap(); final String uuid = transferIDMap.get(id); final Map<String, Object> req = requestMap.get(uuid); map.putString(TYPE, (String) req.get(TYPE)); map.putString(REQUESTID, uuid); map.putDouble(COMPLETEDUNITCOUNT, (double) bytesCurrent); map.putDouble(TOTALUNITCOUNT, (double) bytesTotal); if (bytesTotal == 0) { map.putDouble(FRACTIONCOMPLETED, 0); } else { map.putDouble(FRACTIONCOMPLETED, ((double) bytesCurrent / (double) bytesTotal)); } sendEvent(getReactApplicationContext(), "ProgressEventUtility", map); } @Override public void onError(final int id, final Exception ex) { final WritableMap map = Arguments.createMap(); final WritableMap errorMap = Arguments.createMap(); final String uuid = transferIDMap.get(id); map.putString(REQUESTID, uuid); errorMap.putString(ERROR, ex.toString()); errorMap.putString(DESCRIPTION, ex.getLocalizedMessage()); errorMap.putInt(CODE, ex.hashCode()); map.putMap(ERROR, errorMap); sendEvent(getReactApplicationContext(), "ProgressEventUtility", map); } }); } private void removeTransferFromMap(String uuid, int id) { if (requestMap.get(uuid) != null) { transferUtility.deleteTransferRecord(id); requestMap.remove(uuid); } } private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) { reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params); } }