You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2012/07/28 02:06:21 UTC

ios commit: Change wire format of exec handler.

Updated Branches:
  refs/heads/master b8e0f17dd -> ad836cbb7


Change wire format of exec handler.

The JS now sends commands as a JSON array instead of pre-processed JSON
object. The code maintains compatibility with old-style plugins by
performing the "options" dict extraction on the native side when the
plugin responds to method:withDict: selector. The new way of
implementing native callbacks is to us a method called method:, which is
passed the CDVInvokedUrlCommand.

Update CDVFileTransfer to use the new API.


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

Branch: refs/heads/master
Commit: ad836cbb7afffe49ecc9f28708a910bd325d2527
Parents: b8e0f17
Author: Andrew Grieve <ag...@chromium.org>
Authored: Fri Jul 27 13:34:49 2012 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Fri Jul 27 20:05:40 2012 -0400

----------------------------------------------------------------------
 CordovaLib/Classes/CDVFileTransfer.h              |    6 +-
 CordovaLib/Classes/CDVFileTransfer.m              |   55 ++++++-------
 CordovaLib/Classes/CDVInvokedUrlCommand.h         |   31 +++++--
 CordovaLib/Classes/CDVInvokedUrlCommand.m         |   70 ++++++++++++----
 CordovaLib/Classes/CDVViewController.m            |   36 +++++---
 CordovaLib/CordovaLibTests/CDVFileTransferTests.m |   22 ++++--
 6 files changed, 143 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/ad836cbb/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.h b/CordovaLib/Classes/CDVFileTransfer.h
index 54a37b3..3adbf37 100644
--- a/CordovaLib/Classes/CDVFileTransfer.h
+++ b/CordovaLib/Classes/CDVFileTransfer.h
@@ -41,12 +41,12 @@ extern NSString* const kOptionsKeyCookie;
     
 }
 
-- (void) upload:(NSArray*)arguments withDict:(NSDictionary*)options;
-- (void) download:(NSArray*)arguments withDict:(NSDictionary*)options;
+- (void) upload:(CDVInvokedUrlCommand*)command;
+- (void) download:(CDVInvokedUrlCommand*)command;
 - (NSString*) escapePathComponentForUrlString:(NSString*)urlString;
 
 // Visible for testing.
-- (NSURLRequest*) requestForUpload:(NSArray*)arguments withDict:(NSDictionary*)options fileData:(NSData*)fileData;
+- (NSURLRequest*) requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData:(NSData*)fileData;
 -(NSMutableDictionary*) createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target;
 
 -(NSMutableDictionary*) createFileTransferError:(int)code 

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/ad836cbb/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.m b/CordovaLib/Classes/CDVFileTransfer.m
index 147be32..e831537 100644
--- a/CordovaLib/Classes/CDVFileTransfer.m
+++ b/CordovaLib/Classes/CDVFileTransfer.m
@@ -23,9 +23,9 @@
 
 @interface CDVFileTransfer ()
 // Creates a delegate to handle an upload.
-- (CDVFileTransferDelegate*)delegateForUpload:(NSArray*)arguments;
+- (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command;
 // Creates an NSData* for the file for the given upload arguments.
-- (NSData*)fileDataForUploadArguments:(NSArray*)arguments;
+- (NSData*)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command;
 @end
 
 // Buffer size to use for streaming uploads.
@@ -74,18 +74,17 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) {
     return [schemeAndHost stringByAppendingString:pathComponent];
 }
 
-- (NSURLRequest*) requestForUpload:(NSArray*)arguments withDict:(NSDictionary*)options fileData:(NSData*)fileData {
-    NSString* callbackId = [arguments objectAtIndex:0];
-    
+- (NSURLRequest*) requestForUploadCommand:(CDVInvokedUrlCommand *)command fileData:(NSData *)fileData {
     // arguments order from js: [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode]
     // however, params is a JavaScript object and during marshalling is put into the options dict, 
     // thus debug and chunkedMode are the 6th and 7th arguments
-    
-    NSString* target = (NSString*)[arguments objectAtIndex:1];
-    NSString* server = (NSString*)[arguments objectAtIndex:2];
-    NSString* fileKey = (NSString*)[arguments objectAtIndex:3];
-    NSString* fileName = [arguments objectAtIndex:4 withDefault:@"no-filename"];
-    NSString* mimeType = [arguments objectAtIndex:5 withDefault:nil];
+    NSArray* arguments = command.arguments;
+    NSString* target = (NSString*)[arguments objectAtIndex:0];
+    NSString* server = (NSString*)[arguments objectAtIndex:1];
+    NSString* fileKey = (NSString*)[arguments objectAtIndex:2];
+    NSString* fileName = [arguments objectAtIndex:3 withDefault:@"no-filename"];
+    NSString* mimeType = [arguments objectAtIndex:4 withDefault:nil];
+    NSDictionary* options = [arguments objectAtIndex:5 withDefault:nil];
 //  NSString* trustAllHosts = (NSString*)[arguments objectAtIndex:6]; // allow self-signed certs
     BOOL chunkedMode = [[arguments objectAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue];
 
@@ -113,7 +112,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) {
     if(errorCode > 0) {
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: [self createFileTransferError:errorCode AndSource:target AndTarget:server]];
         
-        [self writeJavascript:[result toErrorCallbackString:callbackId]];
+        [self writeJavascript:[result toErrorCallbackString:command.callbackId]];
         return nil;
     }
     
@@ -228,22 +227,21 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) {
 	return req;
 }
 
-- (CDVFileTransferDelegate*) delegateForUpload:(NSArray*)arguments {
-    NSString* callbackId = [arguments objectAtIndex:0];
-    NSString* target = (NSString*)[arguments objectAtIndex:1];
-    NSString* server = (NSString*)[arguments objectAtIndex:2];
+- (CDVFileTransferDelegate*) delegateForUploadCommand:(CDVInvokedUrlCommand *)command {
+    NSString* target = [command.arguments objectAtIndex:0];
+    NSString* server = [command.arguments objectAtIndex:1];
 
 	CDVFileTransferDelegate* delegate = [[[CDVFileTransferDelegate alloc] init] autorelease];
 	delegate.command = self;
     delegate.direction = CDV_TRANSFER_UPLOAD;
-    delegate.callbackId = callbackId;
+    delegate.callbackId = command.callbackId;
     delegate.source = server;
     delegate.target = target;
     return delegate;
 }
 
-- (NSData*) fileDataForUploadArguments:(NSArray*)arguments {
-    NSString* target = (NSString*)[arguments objectAtIndex:1];
+- (NSData*) fileDataForUploadCommand:(CDVInvokedUrlCommand*)command {
+    NSString* target = (NSString*)[command.arguments objectAtIndex:0];
     NSError *err = nil;
     // Extract the path part out of a file: URL.
     NSString* filePath = [target hasPrefix:@"/"] ? [[target copy] autorelease] : [[NSURL URLWithString:target] path];
@@ -256,19 +254,18 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) {
     return fileData;
 }
 
-- (void) upload:(NSArray*)arguments withDict:(NSDictionary*)options {
+- (void) upload:(CDVInvokedUrlCommand*)command {
     // fileData and req are split into helper functions to ease the unit testing of delegateForUpload.
-    NSData* fileData = [self fileDataForUploadArguments:arguments];
-    NSURLRequest* req = [self requestForUpload:arguments withDict:options fileData:fileData];
-    CDVFileTransferDelegate* delegate = [self delegateForUpload:arguments];
+    NSData* fileData = [self fileDataForUploadCommand:command];
+    NSURLRequest* req = [self requestForUploadCommand:command fileData:fileData];
+    CDVFileTransferDelegate* delegate = [self delegateForUploadCommand:command];
 	[NSURLConnection connectionWithRequest:req delegate:delegate];
 }
 
-- (void) download:(NSArray*)arguments withDict:(NSDictionary*)options {
+- (void) download:(CDVInvokedUrlCommand*)command {
     DLog(@"File Transfer downloading file...");
-    NSString * callbackId = [arguments objectAtIndex:0];
-    NSString * sourceUrl = [arguments objectAtIndex:1];
-    NSString * filePath = [arguments objectAtIndex:2];
+    NSString * sourceUrl = [command.arguments objectAtIndex:0];
+    NSString * filePath = [command.arguments objectAtIndex:1];
     CDVPluginResult *result = nil;
     CDVFileTransferError errorCode = 0;
 
@@ -293,7 +290,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) {
     if(errorCode > 0) {
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: [self createFileTransferError:errorCode AndSource:sourceUrl AndTarget:filePath]];
         
-        [self writeJavascript:[result toErrorCallbackString:callbackId]];
+        [self writeJavascript:[result toErrorCallbackString:command.callbackId]];
         return;
     }
     
@@ -302,7 +299,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) {
     CDVFileTransferDelegate* delegate = [[[CDVFileTransferDelegate alloc] init] autorelease];
 	delegate.command = self;
     delegate.direction = CDV_TRANSFER_DOWNLOAD;
-    delegate.callbackId = callbackId;
+    delegate.callbackId = command.callbackId;
     delegate.source = sourceUrl;
     delegate.target = filePath;
 	

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/ad836cbb/CordovaLib/Classes/CDVInvokedUrlCommand.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInvokedUrlCommand.h b/CordovaLib/Classes/CDVInvokedUrlCommand.h
index b7beb7d..ff7f1ff 100644
--- a/CordovaLib/Classes/CDVInvokedUrlCommand.h
+++ b/CordovaLib/Classes/CDVInvokedUrlCommand.h
@@ -21,19 +21,30 @@
 
 
 @interface CDVInvokedUrlCommand : NSObject {
-	NSString* className;
-	NSString* methodName;
-	NSMutableArray* arguments;
-	NSMutableDictionary* options;
+	NSString* _callbackId;
+	NSString* _className;
+	NSString* _methodName;
+	NSArray* _arguments;
 }
 
-@property(retain) NSMutableArray* arguments;
-@property(retain) NSMutableDictionary* options;
-@property(copy) NSString* className;
-@property(copy) NSString* methodName;
+@property(nonatomic, readonly) NSArray* arguments;
+@property(nonatomic, readonly) NSString* callbackId;
+@property(nonatomic, readonly) NSString* className;
+@property(nonatomic, readonly) NSString* methodName;
 
-+ (CDVInvokedUrlCommand*) commandFromObject:(NSDictionary*)object;
++ (CDVInvokedUrlCommand*) commandFromJson:(NSArray*)jsonEntry;
+
+- (id) initWithArguments:(NSArray*)arguments
+              callbackId:(NSString*)callbackId
+               className:(NSString*)className
+              methodName:(NSString*)methodName;
+              
+- (id) initFromJson:(NSArray*)jsonEntry;
+
+// The first NSDictionary found in the arguments will be returned in legacyDict.
+// The arguments array with be prepended with the callbackId and have the first
+// dict removed from it.
+- (void) legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict;
 
-- (void) dealloc;
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/ad836cbb/CordovaLib/Classes/CDVInvokedUrlCommand.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInvokedUrlCommand.m b/CordovaLib/Classes/CDVInvokedUrlCommand.m
index 45b0a1d..677e5af 100644
--- a/CordovaLib/Classes/CDVInvokedUrlCommand.m
+++ b/CordovaLib/Classes/CDVInvokedUrlCommand.m
@@ -22,28 +22,68 @@
 
 @implementation CDVInvokedUrlCommand
 
-@synthesize arguments;
-@synthesize options;
-@synthesize className;
-@synthesize methodName;
+@synthesize arguments = _arguments;
+@synthesize callbackId = _callbackId;
+@synthesize className = _className;
+@synthesize methodName = _methodName;
 
-+ (CDVInvokedUrlCommand*) commandFromObject:(NSDictionary*)object
++ (CDVInvokedUrlCommand*) commandFromJson:(NSArray*)jsonEntry
 {
-    CDVInvokedUrlCommand* iuc = [[[CDVInvokedUrlCommand alloc] init] autorelease];
-    iuc.className = [object objectForKey:@"className"];
-    iuc.methodName = [object objectForKey:@"methodName"];
-    iuc.arguments = [object objectForKey:@"arguments"];
-    iuc.options = [object objectForKey:@"options"];
+    return [[[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry] autorelease];
+}
+              
+- (id) initFromJson:(NSArray*)jsonEntry
+{
+    NSString* callbackId = [jsonEntry objectAtIndex:0];
+    NSString* className = [jsonEntry objectAtIndex:1];
+    NSString* methodName = [jsonEntry objectAtIndex:2];
+    NSMutableArray* arguments = [jsonEntry objectAtIndex:3];
+    
+    return [self initWithArguments:arguments
+                        callbackId:callbackId
+                         className:className
+                        methodName:methodName];
+}
 
-    return iuc;
+- (id) initWithArguments:(NSArray*)arguments
+              callbackId:(NSString*)callbackId
+               className:(NSString*)className
+              methodName:(NSString*)methodName
+{
+    self = [super init];
+    if (self != nil) {
+        _arguments = [arguments retain];
+        _callbackId = [callbackId retain];
+        _className = [className retain];
+        _methodName = [methodName retain];
+    }
+    return self;
+}
+
+- (void) legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict {
+    NSMutableArray* newArguments = [NSMutableArray arrayWithArray:_arguments];
+    for (NSUInteger i = 0; i < [newArguments count]; ++i) {
+        if ([[newArguments objectAtIndex:i] isKindOfClass:[NSDictionary class]]) {
+            if (legacyDict != NULL) {
+                *legacyDict = [newArguments objectAtIndex:i];
+            }
+            [newArguments removeObjectAtIndex:i];
+            break;
+        }
+    }
+    [newArguments insertObject:_callbackId atIndex:0];
+    if (legacyArguments != NULL) {
+        *legacyArguments = newArguments;
+    }
 }
 
+
 - (void) dealloc
 {
-    [arguments release];
-    [options release];
-    [className release];
-    [methodName release];
+    [_arguments release];
+    [_callbackId release];
+    [_className release];
+    [_methodName release];
     
     [super dealloc];
 }

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/ad836cbb/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m
index bd99ecc..63b2de0 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -767,21 +767,21 @@ BOOL gSplashScreenShown = NO;
 	
 	
     // Parse the returned JSON array.
-    NSArray* queuedCommands =
-	[queuedCommandsJSON cdvjk_objectFromJSONString];
+    NSArray* queuedCommands = [queuedCommandsJSON cdvjk_mutableObjectFromJSONString];
 	
     // Iterate over and execute all of the commands.
-    for (NSString* commandJson in queuedCommands) {
-		
-        if(![self.commandDelegate execute:
-		 [CDVInvokedUrlCommand commandFromObject:
-		  [commandJson cdvjk_mutableObjectFromJSONString]]])
-		{
+    for (NSArray* jsonEntry in queuedCommands) {
+        CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
+        if(![self.commandDelegate execute:command]) {
+#ifdef DEBUG
+            NSString* commandJson = [jsonEntry cdvjk_JSONString];
             static NSUInteger maxLogLength = 1024;
             NSString* commandString = ([commandJson length] > maxLogLength) ? 
                 [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] : 
                 commandJson;
+
 			DLog(@"FAILED pluginJSON = %@", commandString);
+#endif
 		}
     }
 	
@@ -824,16 +824,24 @@ BOOL gSplashScreenShown = NO;
     }
     BOOL retVal = YES;
     
-    // construct the fill method name to ammend the second argument.
-    NSString* fullMethodName = [[NSString alloc] initWithFormat:@"%@:withDict:", command.methodName];
-    if ([obj respondsToSelector:NSSelectorFromString(fullMethodName)]) {
-        [obj performSelector:NSSelectorFromString(fullMethodName) withObject:command.arguments withObject:command.options];
+    // Find the proper selector to call.
+    NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName];
+    NSString* methodNameWithDict = [NSString stringWithFormat:@"%@:withDict:", command.methodName];
+    SEL normalSelector = NSSelectorFromString(methodName);
+    SEL legacySelector = NSSelectorFromString(methodNameWithDict);
+    // Test for the legacy selector first in case they both exist.
+    if ([obj respondsToSelector:legacySelector]) {
+        NSMutableArray* arguments = nil;
+        NSMutableDictionary* dict = nil;
+        [command legacyArguments:&arguments andDict:&dict];
+        [obj performSelector:legacySelector withObject:arguments withObject:dict];
+    } else if ([obj respondsToSelector:normalSelector]) {
+        [obj performSelector:normalSelector withObject:command];
     } else {
         // There's no method to call, so throw an error.
-        NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", fullMethodName, command.className);
+        NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className);
         retVal = NO;
     }
-    [fullMethodName release];
     
     return retVal;
 }

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/ad836cbb/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
----------------------------------------------------------------------
diff --git a/CordovaLib/CordovaLibTests/CDVFileTransferTests.m b/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
index 6e2fcf7..6c2b929 100644
--- a/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
+++ b/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
@@ -60,8 +60,9 @@ static NSData* readStream(NSInputStream* stream) {
 - (void)setUp
 {
     [super setUp];
+    
     _arguments = [[NSMutableArray alloc] initWithObjects:
-        kDummyArgCallbackId, kDummyArgTarget, kDummyArgServer, kDummyArgFileKey,
+        kDummyArgTarget, kDummyArgServer, kDummyArgFileKey, [NSNull null],
         [NSNull null], [NSNull null], [NSNull null], [NSNull null], nil];
     _dummyFileData = [[kDummyFileContents dataUsingEncoding:NSUTF8StringEncoding] retain];
     _fileTransfer = [[CDVFileTransfer alloc] init];
@@ -79,19 +80,27 @@ static NSData* readStream(NSInputStream* stream) {
 }
 
 - (void)setFilePathArg:(NSString*)filePath {
-    [_arguments replaceObjectAtIndex:1 withObject:filePath];
+    [_arguments replaceObjectAtIndex:0 withObject:filePath];
 }
 
 - (void)setServerUrlArg:(NSString*)serverUrl {
-    [_arguments replaceObjectAtIndex:2 withObject:serverUrl];
+    [_arguments replaceObjectAtIndex:1 withObject:serverUrl];
 }
 
 - (void)setChunkedModeArg:(BOOL)chunk {
     [_arguments replaceObjectAtIndex:7 withObject:[NSNumber numberWithBool:chunk]];
 }
 
+- (void)setParams:(NSDictionary*)params {
+    [_arguments replaceObjectAtIndex:5 withObject:params];
+}
+
 - (NSURLRequest*)requestForUpload {
-    return [_fileTransfer requestForUpload:_arguments withDict:nil fileData:_dummyFileData];
+    CDVInvokedUrlCommand* command = [[[CDVInvokedUrlCommand alloc] initWithArguments:_arguments
+                                                                          callbackId:kDummyArgCallbackId
+                                                                           className:@"FileTransfer"
+                                                                          methodName:@"upload"] autorelease];
+    return [_fileTransfer requestForUploadCommand:command fileData:_dummyFileData];
 }
 
 - (void)checkUploadRequest:(NSURLRequest*)request chunked:(BOOL)chunked {
@@ -166,9 +175,10 @@ static NSData* readStream(NSInputStream* stream) {
     [self setChunkedModeArg:NO];
     NSDictionary* headers = [NSDictionary dictionaryWithObjectsAndKeys:@"val1", @"key1",
         @"val2", @"key2", nil];
-    NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:@"cookieval", kOptionsKeyCookie,
+    NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys:@"cookieval", kOptionsKeyCookie,
         headers, @"headers", @"val3", @"key3", nil];
-    NSURLRequest* request = [_fileTransfer requestForUpload:_arguments withDict:options fileData:_dummyFileData];
+    [self setParams:params];
+    NSURLRequest* request = [self requestForUpload];
     NSString* payload = [[[NSString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding] autorelease];
     // Check that headers are properly set.
     STAssertTrue([@"val1" isEqualToString:[request valueForHTTPHeaderField:@"key1"]], nil);