incubator-callback-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fil...@apache.org
Subject [12/28] git commit: Add download functionality to filetransfer API.
Date Tue, 03 Jan 2012 20:22:58 GMT
Add download functionality to filetransfer API.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/commit/f91fee35
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/tree/f91fee35
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/diff/f91fee35

Branch: refs/heads/master
Commit: f91fee3541132e68afa4a69d5eed6c51768eec30
Parents: 3e6ea17
Author: Drew Walters <deedubbu@gmail.com>
Authored: Fri Dec 9 06:52:10 2011 +0800
Committer: Drew Walters <deedubbu@gmail.com>
Committed: Fri Dec 9 06:54:19 2011 +0800

----------------------------------------------------------------------
 .../ext/src/com/phonegap/http/FileTransfer.java    |  388 ++++++++++++---
 javascript/filetransfer.js                         |  113 +++--
 2 files changed, 394 insertions(+), 107 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/f91fee35/framework/ext/src/com/phonegap/http/FileTransfer.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/com/phonegap/http/FileTransfer.java b/framework/ext/src/com/phonegap/http/FileTransfer.java
index c791c55..53164c6 100644
--- a/framework/ext/src/com/phonegap/http/FileTransfer.java
+++ b/framework/ext/src/com/phonegap/http/FileTransfer.java
@@ -1,119 +1,365 @@
 /*
  * PhoneGap is available under *either* the terms of the modified BSD license *or* the
  * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- * 
+ *
  * Copyright (c) 2005-2010, Nitobi
- * Copyright (c) 2010, IBM Corporation
- */ 
+ * Copyright (c) 2010-2011, IBM Corporation
+ */
 package com.phonegap.http;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.HttpConnection;
+import javax.microedition.io.file.FileConnection;
 
 import net.rim.device.api.io.FileNotFoundException;
+import net.rim.device.api.io.http.HttpProtocolConstants;
 
 import com.phonegap.api.Plugin;
 import com.phonegap.api.PluginResult;
+import com.phonegap.file.Entry;
 import com.phonegap.json4j.JSONArray;
 import com.phonegap.json4j.JSONException;
 import com.phonegap.json4j.JSONObject;
 import com.phonegap.util.Logger;
 
 /**
- * The FileTransfer plugin can be used to transfer files between the device and 
- * a remote server.
+ * The FileTransfer plugin can be used to transfer files between the device and
+ * a remote server. The following actions are supported:
+ *
+ *      download - Download a file from a server to the device.
+ *      upload   - Upload a file from the device to a server.
  */
 public class FileTransfer extends Plugin {
+    private static final String LOG_TAG = "FileTransfer: ";
 
     /**
      * Error codes
      */
-    public static int FILE_NOT_FOUND_ERR = 1;
-    public static int INVALID_URL_ERR = 2;
-    public static int CONNECTION_ERR = 3;
-    
+    static int FILE_NOT_FOUND_ERR = 1;
+    static int INVALID_URL_ERR = 2;
+    static int CONNECTION_ERR = 3;
+
     /**
      * Possible actions
      */
-    protected static final int ACTION_UPLOAD = 0;
+    private static final String ACTION_DOWNLOAD = "download";
+    private static final String ACTION_UPLOAD = "upload";
+
+    private static final char SEPARATOR = '/';
 
     /**
      * Executes the requested action and returns a PluginResult.
-     * 
-     * @param action        The action to execute.
-     * @param callbackId    The callback ID to be invoked upon action completion.
-     * @param args          JSONArry of arguments for the action.
-     * @return              A PluginResult object with a status and message.
+     *
+     * @param action
+     *            The action to execute.
+     * @param callbackId
+     *            The callback ID to be invoked upon action completion.
+     * @param args
+     *            JSONArry of arguments for the action.
+     * @return A PluginResult object with a status and message.
      */
     public PluginResult execute(String action, JSONArray args, String callbackId) {
-
-        // perform specified action
+        String source = null;
+        String target = null;
         PluginResult result = null;
-        int a = getAction(action);
-        if (a == ACTION_UPLOAD) {
+
+        try {
+            // Retrieve the source and target locations from the argument array.
+            source = args.isNull(0) ? null : args.getString(0).trim();
+            target = args.isNull(1) ? null : args.getString(1).trim();
+
+            if (source == null || source.length() == 0 || target == null
+                    || target.length() == 0) {
+                Logger.log(LOG_TAG + "Missing source or target");
+                return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+                        "Missing source or target");
+            }
+        } catch (JSONException e) {
+            Logger.log(LOG_TAG + e.getMessage());
+            return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+                    "Invalid or missing parameter");
+        }
+
+        if (ACTION_UPLOAD.equals(action)) {
+            // Source needs to follow the file URI protocol so add "file:///"
+            // prefix if it doesn't exist.
+            if (!source.startsWith("file:///")) {
+                if (source.indexOf(SEPARATOR) != 0) {
+                    source = "file://" + SEPARATOR + source;
+                } else {
+                    source = "file://" + source;
+                }
+            }
+
             try {
-                // required parameters
-                String filePath = args.getString(0);    
-                String server = args.getString(1);
-
-                // user parameters
-                String fileKey = "file";
-                String fileName = "image.jpg";
-                String mimeType = null;
+                // Setup the options
+                String fileKey = getArgument(args, 2, "file");
+                String fileName = getArgument(args, 3, "image.jpg");
+                String mimeType = getArgument(args, 4, null);
                 JSONObject params = null;
-                if(args.length() > 2 && !args.isNull(2)) {
-                    fileKey = args.optString(2);
-                }
-                if(args.length() > 3 && !args.isNull(3)) {
-                    fileName = args.optString(3);
-                }
-                if(args.length() > 4 && !args.isNull(4)) {
-                    mimeType = args.optString(4);
-                }
+
                 if (args.length() > 5 && !args.isNull(5)) {
-                    params = args.getJSONObject(5);    
+                    params = args.getJSONObject(5);
                 }
 
                 FileUploader f = new FileUploader();
-                FileUploadResult r = f.upload(filePath, server, fileKey, fileName, mimeType,
params);
-                result = new PluginResult(PluginResult.Status.OK, r.toJSONObject());
-            } 
-            catch (FileNotFoundException e) {
-                Logger.log(this.getClass().getName() + ": " + e);
-                return new PluginResult(PluginResult.Status.IO_EXCEPTION, 
-                        Integer.toString(FILE_NOT_FOUND_ERR));
-            } 
-            catch (IllegalArgumentException e) {
-                Logger.log(this.getClass().getName() + ": " + e);
-                return new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION,
-                        Integer.toString(INVALID_URL_ERR));
-            }
-            catch (IOException e) {
-                Logger.log(this.getClass().getName() + ": " + e);
-                return new PluginResult(PluginResult.Status.IO_EXCEPTION, 
-                        Integer.toString(CONNECTION_ERR));
-            } 
-            catch (JSONException e) {
-                Logger.log(this.getClass().getName() + ": " + e);
-                return new PluginResult(PluginResult.Status.JSON_EXCEPTION, 
+                FileUploadResult r = f.upload(source, target, fileKey,
+                        fileName, mimeType, params);
+                result = new PluginResult(PluginResult.Status.OK,
+                        r.toJSONObject());
+            } catch (FileNotFoundException e) {
+                Logger.log(LOG_TAG + e.getMessage());
+                JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR,
+                        source, target);
+                result = new PluginResult(PluginResult.Status.IO_EXCEPTION,
+                        error);
+            } catch (IllegalArgumentException e) {
+                Logger.log(LOG_TAG + e.getMessage());
+                JSONObject error = createFileTransferError(INVALID_URL_ERR,
+                        source, target);
+                result = new PluginResult(
+                        PluginResult.Status.MALFORMED_URL_EXCEPTION, error);
+            } catch (IOException e) {
+                Logger.log(LOG_TAG + e.getMessage());
+                JSONObject error = createFileTransferError(CONNECTION_ERR,
+                        source, target);
+                result = new PluginResult(PluginResult.Status.IO_EXCEPTION,
+                        error);
+            } catch (JSONException e) {
+                Logger.log(LOG_TAG + e.getMessage());
+                result = new PluginResult(PluginResult.Status.JSON_EXCEPTION,
                         "Invalid or missing parameter");
             }
-        } 
-        else {
+        } else if (ACTION_DOWNLOAD.equals(action)) {
+            result = download(source, target);
+        } else {
             // invalid action
-            result = new PluginResult(PluginResult.Status.INVALID_ACTION, 
-                    "File: invalid action " + action);
+            result = new PluginResult(PluginResult.Status.INVALID_ACTION,
+                    LOG_TAG + "invalid action " + action);
         }
-        
+
         return result;
     }
-    
+
+    /**
+     * Create an error object based on the passed in errorCode
+     *
+     * @param errorCode
+     *            the error
+     * @return JSONObject containing the error
+     */
+    private JSONObject createFileTransferError(int errorCode, String source,
+            String target) {
+        JSONObject error = null;
+        try {
+            error = new JSONObject();
+            error.put("code", errorCode);
+            error.put("source", source);
+            error.put("target", target);
+        } catch (JSONException e) {
+            Logger.log(LOG_TAG + e.getMessage());
+        }
+        return error;
+    }
+
+    /**
+     * Recurse through a specified path and create any directories that do not
+     * already exist.
+     *
+     * @param path
+     *            directory path to recurse
+     * @throws IOException
+     */
+    private void createSubDirs(String path) throws IOException {
+        FileConnection outputStream = null;
+
+        try {
+            outputStream = (FileConnection) Connector.open(path,
+                    Connector.READ_WRITE);
+            if (!outputStream.exists()) {
+                int dirIndex = path.lastIndexOf(SEPARATOR, path.length() - 2);
+                // This code assumes file protocol is specified so stop
+                // recursion once "file:///" is hit.
+                if (dirIndex != -1 && dirIndex > 7) {
+                    createSubDirs(path.substring(0, dirIndex + 1));
+                }
+                outputStream.mkdir();
+            }
+        } finally {
+            try {
+                if (outputStream != null) {
+                    outputStream.close();
+                }
+            } catch (IOException e) {
+                Logger.log(LOG_TAG + e.getMessage());
+            }
+        }
+    }
+
     /**
-     * Returns action to perform.
-     * @param action action to perform
-     * @return action to perform
+     * Download a file from a given URL and save it to the specified location.
+     *
+     * @param source
+     *            URL of the server to receive the file
+     * @param target
+     *            Full path of the file on the file system
+     * @return JSONObject a file entry object in JSON form describing the
+     *         downloaded file.
      */
-    protected static int getAction(String action) {
-        if ("upload".equals(action)) return ACTION_UPLOAD;
-        return -1;
-    }    
+    private PluginResult download(String source, String target) {
+        HttpConnection httpConn = null;
+        FileConnection fileConn = null;
+        OutputStream outputStream = null;
+        String filename = null;
+        String path = null;
+
+        // Target needs to follow the file URI protocol so add "file:///"
+        // prefix if it doesn't exist.
+        if (!target.startsWith("file:///")) {
+            if (target.indexOf(SEPARATOR) != 0) {
+                target = "file://" + SEPARATOR + target;
+            } else {
+                target = "file://" + target;
+            }
+        }
+
+        // Parse the target filename and directory path. If the target does not
+        // specify a file name (only directory), try to get the file name from
+        // the source.
+        int dirIndex = target.lastIndexOf(SEPARATOR);
+        if (dirIndex == (target.length() - 1)) {
+            int srcdirIndex = source.lastIndexOf(SEPARATOR);
+            if (srcdirIndex != (source.length() - 1)) {
+                path = target;
+                filename = source.substring(srcdirIndex + 1);
+                target = path + filename;
+            }
+        } else if (dirIndex != -1) {
+            filename = target.substring(dirIndex + 1);
+            path = target.substring(0, dirIndex + 1);
+        }
+
+        // If no filename or path could be determined for the target, error out.
+        if (filename == null || path == null) {
+            Logger.log(LOG_TAG + "Target filename could not be determined.");
+            JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR,
+                    source, target);
+            return new PluginResult(PluginResult.Status.JSON_EXCEPTION, error);
+        }
+
+        try {
+            // Create any directories in the path that do not already exist.
+            createSubDirs(path);
+
+            // Open connection to the target file.
+            fileConn = (FileConnection) Connector.open(target,
+                    Connector.READ_WRITE);
+
+            // Create the target file if it doesn't exist, otherwise truncate.
+            if (!fileConn.exists()) {
+                fileConn.create();
+            } else {
+                fileConn.truncate(0);
+            }
+
+            // Open the http connection to the server.
+            httpConn = HttpUtils.getHttpConnection(source);
+            if (httpConn == null) {
+                Logger.log(LOG_TAG + "Failed to create http connection.");
+                JSONObject error = createFileTransferError(INVALID_URL_ERR,
+                        source, target);
+                return new PluginResult(
+                        PluginResult.Status.MALFORMED_URL_EXCEPTION, error);
+            }
+
+            // Set the request headers
+            httpConn.setRequestMethod(HttpConnection.GET);
+            httpConn.setRequestProperty(
+                    HttpProtocolConstants.HEADER_USER_AGENT,
+                    System.getProperty("browser.useragent"));
+            httpConn.setRequestProperty(
+                    HttpProtocolConstants.HEADER_KEEP_ALIVE, "300");
+            httpConn.setRequestProperty(
+                    HttpProtocolConstants.HEADER_CONNECTION, "keep-alive");
+
+            // Set the cookie
+            String cookie = HttpUtils.getCookie(source);
+            if (cookie != null) {
+                httpConn.setRequestProperty(
+                        HttpProtocolConstants.HEADER_COOKIE, cookie);
+            }
+
+            InputStream inputStream = httpConn.openInputStream();
+            outputStream = fileConn.openOutputStream();
+
+            // Read from the connection and write bytes to the file.
+            byte[] buffer = new byte[1024];
+            int bytesRead = 0;
+            while ((bytesRead = inputStream.read(buffer)) > 0) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+        } catch (IOException e) {
+            Logger.log(LOG_TAG + e.getMessage());
+            JSONObject error = createFileTransferError(CONNECTION_ERR, source,
+                    target);
+            return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+        } catch (ClassCastException e) {
+            // in case something really funky gets passed in
+            Logger.log(LOG_TAG + e.getMessage());
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source,
+                    target);
+            return new PluginResult(
+                    PluginResult.Status.MALFORMED_URL_EXCEPTION, error);
+        } finally {
+            try {
+                if (httpConn != null) {
+                    httpConn.close();
+                }
+                if (outputStream != null) {
+                    outputStream.close();
+                }
+                if (fileConn != null) {
+                    fileConn.close();
+                }
+            } catch (IOException e) {
+                Logger.log(LOG_TAG + "IOException in finally: "
+                        + e.getMessage());
+            }
+        }
+
+        // create a new Entry
+        Entry entry = new Entry();
+        entry.setDirectory(false);
+        entry.setName(filename);
+        entry.setFullPath(target);
+
+        return new PluginResult(PluginResult.Status.OK, entry.toJSONObject());
+    }
+
+    /**
+     * Convenience method to read a parameter from the list of JSON args.
+     *
+     * @param args
+     *            the args passed to the Plugin
+     * @param position
+     *            the position to retrieve the arg from
+     * @param defaultString
+     *            the default to be used if the arg does not exist
+     * @return String with the retrieved value
+     */
+    private String getArgument(JSONArray args, int position,
+            String defaultString) {
+        String arg = defaultString;
+        if (args.length() >= position) {
+            arg = args.optString(position);
+            if (arg == null || "null".equals(arg)) {
+                arg = defaultString;
+            }
+        }
+        return arg;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/f91fee35/javascript/filetransfer.js
----------------------------------------------------------------------
diff --git a/javascript/filetransfer.js b/javascript/filetransfer.js
index e174feb..ff7d8d3 100644
--- a/javascript/filetransfer.js
+++ b/javascript/filetransfer.js
@@ -1,20 +1,25 @@
-
 /*
  * PhoneGap is available under *either* the terms of the modified BSD license *or* the
  * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *  
+ *
  * Copyright (c) 2005-2010, Nitobi Software Inc.
  * Copyright (c) 2010-2011, IBM Corporation
  */
 
 /**
  * Options to customize the HTTP request used to upload files.
- * @param fileKey {String}   Name of file request parameter.
- * @param fileName {String}  Filename to be used by the server. Defaults to image.jpg.
- * @param mimeType {String}  Mimetype of the uploaded file. Defaults to image/jpeg.
- * @param params {Object}    Object with key: value params to send to the server.
+ *
+ * @constructor
+ * @param fileKey
+ *            {String} Name of file request parameter.
+ * @param fileName
+ *            {String} Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType
+ *            {String} Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params
+ *            {Object} Object with key: value params to send to the server.
  */
-function FileUploadOptions(fileKey, fileName, mimeType, params) {
+var FileUploadOptions = function(fileKey, fileName, mimeType, params) {
     this.fileKey = fileKey || null;
     this.fileName = fileName || null;
     this.mimeType = mimeType || null;
@@ -22,9 +27,20 @@ function FileUploadOptions(fileKey, fileName, mimeType, params) {
 };
 
 /**
+ * FileUploadResult
+ * @constructor
+ */
+var FileUploadResult = function() {
+    this.bytesSent = 0;
+    this.responseCode = null;
+    this.response = null;
+};
+
+/**
  * FileTransferError
+ * @constructor
  */
-function FileTransferError() {
+var FileTransferError = function() {
     this.code = null;
 };
 
@@ -41,50 +57,75 @@ var FileTransfer = FileTransfer || (function() {
      */
     function FileTransfer() {
     };
-    
+
     /**
-     * Given an absolute file path, uploads a file on the device to a remote server 
-     * using a multipart HTTP request.
-     * @param filePath {String}           Full path of the file on the device
-     * @param server {String}             URL of the server to receive the file
-     * @param successCallback (Function}  Callback to be invoked when upload has completed
-     * @param errorCallback {Function}    Callback to be invoked upon error
-     * @param options {FileUploadOptions} Optional parameters such as file name and mimetype
          
+     * Given an absolute file path, uploads a file on the device to a remote
+     * server using a multipart HTTP request.
+     *
+     * @param filePath
+     *            {String} Full path of the file on the device
+     * @param server
+     *            {String} URL of the server to receive the file
+     * @param successCallback
+     *            (Function} Callback to be invoked when upload has completed
+     * @param errorCallback
+     *            {Function} Callback to be invoked upon error
+     * @param options
+     *            {FileUploadOptions} Optional parameters such as file name and
+     *            mimetype
      */
-    FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback,
options) {
+    FileTransfer.prototype.upload = function(filePath, server, successCallback,
+            errorCallback, options, debug) {
 
         // check for options
         var fileKey = null;
         var fileName = null;
         var mimeType = null;
         var params = null;
+        var chunkedMode = true;
         if (options) {
             fileKey = options.fileKey;
             fileName = options.fileName;
             mimeType = options.mimeType;
-            params = options.params;
-        }
-            
-        // error callback
-        var fail = function(error) {
-            var err = new FileTransferError();
-            err.code = error;
-            if (typeof errorCallback === "function") {
-                errorCallback(err);
+            if (options.chunkedMode !== null
+                    || typeof options.chunkedMode !== "undefined") {
+                chunkedMode = options.chunkedMode;
             }
-        };
-        
-        PhoneGap.exec(successCallback, fail, 'FileTransfer', 'upload', 
-                [filePath, server, fileKey, fileName, mimeType, params]);
+            if (options.params) {
+                params = options.params;
+            } else {
+                params = {};
+            }
+        }
+
+        PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload',
+                [ filePath, server, fileKey, fileName, mimeType, params, debug,
+                        chunkedMode ]);
     };
-    
+
     /**
-     * FileUploadResult
+     * Downloads a file form a given URL and saves it to the specified
+     * directory.
+     *
+     * @param source
+     *            {String} URL of the server to receive the file
+     * @param target
+     *            {String} Full path of the file on the device
+     * @param successCallback
+     *            (Function} Callback to be invoked when upload has completed
+     * @param errorCallback
+     *            {Function} Callback to be invoked upon error
      */
-    function FileUploadResult() {
-        this.bytesSent = 0;
-        this.responseCode = null;
-        this.response = null;
+    FileTransfer.prototype.download = function(source, target, successCallback,
+            errorCallback) {
+        var castSuccess = function(entry) {
+            if (typeof successCallback === "function") {
+                var fileEntry = new FileEntry(entry);
+                successCallback(entry);
+            }
+        };
+        PhoneGap.exec(castSuccess, errorCallback, 'FileTransfer',
+                'download', [ source, target ]);
     };
 
     return FileTransfer;


Mime
View raw message