You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by ga...@apache.org on 2014/05/21 14:51:01 UTC

svn commit: r1596563 [4/4] - in /chemistry/objectivecmis/trunk: ./ ObjectiveCMIS.xcodeproj/ ObjectiveCMIS.xcodeproj/xcshareddata/xcschemes/ ObjectiveCMIS/Bindings/ ObjectiveCMIS/Bindings/AtomPub/ ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/ ObjectiveC...

Modified: chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h Wed May 21 12:50:59 2014
@@ -39,11 +39,8 @@
                          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
 
 /**
- * starts a URL request with a provided input stream. The input stream has to point to the raw NON-encoded data set. This method will use the
- * provided CMIS properties and mimeType to create the appropriate XML data. The base 64 encoding will be done while the data are being read in
- * from the source input stream.
- * In order to achieve this, the pairing an OutputStream (where we will write the XML and base64 data to) with a resulting fully base64 encoded
- * input stream. This base64 encoded inputstream will be passed on to the NSMutableURLRequest via its HTTPBodyStream property/method.
+ * starts a URL request with a provided input stream. The input stream has to point to the raw NON-encoded data set. This method will first write the 
+ * provided start data, afterwards the content of the input stream (optionally encoding it as base64) and then the provided end data.
  */
 + (id)startRequest:(NSMutableURLRequest *)urlRequest
         httpMethod:(CMISHttpRequestMethod)httpRequestMethod
@@ -51,8 +48,9 @@
            headers:(NSDictionary*)additionalHeaders
      bytesExpected:(unsigned long long)bytesExpected
 authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
-    cmisProperties:(CMISProperties *)cmisProperties
-          mimeType:(NSString *)mimeType
+         startData:(NSData *)startData
+           endData:(NSData *)endData
+ useBase64Encoding:(BOOL)useBase64Encoding
    completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
      progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
 

Modified: chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m Wed May 21 12:50:59 2014
@@ -85,8 +85,9 @@ const NSUInteger kRawBufferSize = 24576;
 
 @property (nonatomic, assign) unsigned long long bytesUploaded;
 @property (nonatomic, copy) void (^progressBlock)(unsigned long long bytesUploaded, unsigned long long bytesTotal);
+@property (nonatomic, assign) BOOL useCombinedInputStream;
 @property (nonatomic, assign) BOOL base64Encoding;
-@property (nonatomic, strong) NSInputStream *base64InputStream;
+@property (nonatomic, strong) NSInputStream *combinedInputStream;
 @property (nonatomic, strong) NSOutputStream *encoderStream;
 @property (nonatomic, strong) NSData *streamStartData;
 @property (nonatomic, strong) NSData *streamEndData;
@@ -95,15 +96,6 @@ const NSUInteger kRawBufferSize = 24576;
 @property (nonatomic, assign, readwrite) size_t bufferOffset;
 @property (nonatomic, assign, readwrite) size_t bufferLimit;
 
-- (void)stopSendWithStatus:(NSString *)statusString;
-+ (unsigned long long)base64EncodedLength:(unsigned long long)contentSize;
-- (void)prepareXMLWithCMISProperties:(CMISProperties *)cmisProperties mimeType:(NSString *)mimeType;
-- (void)prepareStreams;
-
-- (id)initWithHttpMethod:(CMISHttpRequestMethod)httpRequestMethod
-         completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-           progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
-
 @end
 
 
@@ -125,8 +117,8 @@ const NSUInteger kRawBufferSize = 24576;
     httpRequest.additionalHeaders = additionalHeaders;
     httpRequest.bytesExpected = bytesExpected;
     httpRequest.authenticationProvider = authenticationProvider;
-    httpRequest.base64Encoding = NO;
-    httpRequest.base64InputStream = nil;
+    httpRequest.useCombinedInputStream = NO;
+    httpRequest.combinedInputStream = nil;
     httpRequest.encoderStream = nil;
     
     if (![httpRequest startRequest:urlRequest]) {
@@ -138,27 +130,30 @@ const NSUInteger kRawBufferSize = 24576;
 
 + (id)startRequest:(NSMutableURLRequest *)urlRequest
         httpMethod:(CMISHttpRequestMethod)httpRequestMethod
-       inputStream:(NSInputStream*)inputStream
-           headers:(NSDictionary*)addionalHeaders
+       inputStream:(NSInputStream *)inputStream
+           headers:(NSDictionary *)additionalHeaders
      bytesExpected:(unsigned long long)bytesExpected
-authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
-    cmisProperties:(CMISProperties *)cmisProperties
-          mimeType:(NSString *)mimeType
-   completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+authenticationProvider:(id<CMISAuthenticationProvider>)authenticationProvider
+         startData:(NSData *)startData
+           endData:(NSData *)endData
+ useBase64Encoding:(BOOL)useBase64Encoding
+   completionBlock:(void (^)(CMISHttpResponse *, NSError *))completionBlock
+     progressBlock:(void (^)(unsigned long long, unsigned long long))progressBlock
 {
     CMISHttpUploadRequest *httpRequest = [[self alloc] initWithHttpMethod:httpRequestMethod
                                                           completionBlock:completionBlock
                                                             progressBlock:progressBlock];
     
     httpRequest.inputStream = inputStream;
-    httpRequest.additionalHeaders = addionalHeaders;
+    httpRequest.streamStartData = startData;
+    httpRequest.streamEndData = endData;
+    httpRequest.additionalHeaders = additionalHeaders;
     httpRequest.bytesExpected = bytesExpected;
-    httpRequest.base64Encoding = YES;
+    httpRequest.useCombinedInputStream = YES;
+    httpRequest.base64Encoding = useBase64Encoding;
     httpRequest.authenticationProvider = authenticationProvider;
     
     [httpRequest prepareStreams];
-    [httpRequest prepareXMLWithCMISProperties:cmisProperties mimeType:mimeType];
     if (![httpRequest startRequest:urlRequest]) {
         httpRequest = nil;
     }
@@ -181,19 +176,21 @@ authenticationProvider:(id<CMISAuthentic
 
 
 /**
- if we are using on-the-go base64 encoding, we will use the base64InputStream in URL connections/request.
+ if we are using on-the-go base64 encoding, we will use the combinedInputStream in URL connections/request.
  In this case a little extra work is required: i.e. we need to provide the length of the encoded data stream (including
  the XML data).
  */
 - (BOOL)startRequest:(NSMutableURLRequest*)urlRequest
 {
-    if (self.base64Encoding)
+    if (self.useCombinedInputStream)
     {
-        if (self.base64InputStream) {
-            urlRequest.HTTPBodyStream = self.base64InputStream;
-            NSMutableDictionary *headers = [NSMutableDictionary dictionaryWithDictionary:self.additionalHeaders];
-            [headers setValue:[NSString stringWithFormat:@"%llu", self.encodedLength] forKey:@"Content-Length"];
-            self.additionalHeaders = [NSDictionary dictionaryWithDictionary:headers];
+        if (self.combinedInputStream) {
+            urlRequest.HTTPBodyStream = self.combinedInputStream;
+            if(self.base64Encoding) {
+                NSMutableDictionary *headers = [NSMutableDictionary dictionaryWithDictionary:self.additionalHeaders];
+                [headers setValue:[NSString stringWithFormat:@"%llu", self.encodedLength] forKey:@"Content-Length"];
+                self.additionalHeaders = [NSDictionary dictionaryWithDictionary:headers];
+            }
         }
     }
     else
@@ -203,7 +200,7 @@ authenticationProvider:(id<CMISAuthentic
         }
     }
     BOOL startSuccess = [super startRequest:urlRequest];
-    if (self.base64Encoding) {
+    if (self.useCombinedInputStream) {
         [self.encoderStream open];
     }
 
@@ -216,7 +213,7 @@ authenticationProvider:(id<CMISAuthentic
     self.progressBlock = nil;
     
     [super cancel];
-    if (self.base64Encoding) {
+    if (self.useCombinedInputStream) {
         [self stopSendWithStatus:@"connection has been cancelled."];
     }
 }
@@ -235,7 +232,7 @@ authenticationProvider:(id<CMISAuthentic
 totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
 {
     if (self.progressBlock) {
-        if (self.base64Encoding) {
+        if (self.useCombinedInputStream && self.base64Encoding) {
             // Show the actual transmitted raw data size to the user, not the base64 encoded size
             totalBytesWritten = [CMISHttpUploadRequest rawEncodedLength:totalBytesWritten];
             if (totalBytesWritten > totalBytesExpectedToWrite) {
@@ -260,7 +257,7 @@ totalBytesExpectedToWrite:(NSInteger)tot
 {
     [super connection:connection didFailWithError:error];
     
-    if (self.base64Encoding) {
+    if (self.useCombinedInputStream) {
         [self stopSendWithStatus:@"connection is being terminated with error."];
     }
     self.progressBlock = nil;
@@ -274,7 +271,7 @@ totalBytesExpectedToWrite:(NSInteger)tot
 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
 {
     [super connectionDidFinishLoading:connection];
-    if (self.base64Encoding) {
+    if (self.useCombinedInputStream) {
         [self stopSendWithStatus:@"Connection finished as expected."];
     }
     
@@ -287,9 +284,9 @@ totalBytesExpectedToWrite:(NSInteger)tot
  The action is in the case where the eventCode == NSStreamEventHasSpaceAvailable
  
  Note 1:
- The output stream (encoderStream) is paired with the encoded input stream (base64InputStream) which is the one
+ The output stream (encoderStream) is paired with the encoded input stream (combinedInputStream) which is the one
  the active URL connection uses to read from. Thereby any data made available to the outputstream will be available to this input stream as well.
- Any action on the output stream (like close) will also affect this base64InputStream.
+ Any action on the output stream (like close) will also affect this combinedInputStream.
  
  Note 2:
  since we are encoding "on the fly" we are dealing with 2 different buffer sizes. The encoded buffer size kFullBufferSize, and the
@@ -311,8 +308,8 @@ totalBytesExpectedToWrite:(NSInteger)tot
 {
     switch (eventCode){
         case NSStreamEventOpenCompleted:{
-            if (self.base64InputStream.streamStatus != NSStreamStatusOpen) {
-                [self.base64InputStream open]; // this seems to work around the 'Stream ... is sending an event before being opened' Apple bug
+            if (self.combinedInputStream.streamStatus != NSStreamStatusOpen) {
+                [self.combinedInputStream open]; // this seems to work around the 'Stream ... is sending an event before being opened' Apple bug
             }
             if (self.inputStream.streamStatus != NSStreamStatusOpen) {
                 [self.inputStream open];
@@ -325,14 +322,14 @@ totalBytesExpectedToWrite:(NSInteger)tot
             break;
 
         case NSStreamEventHasSpaceAvailable: {
-            if (self.base64InputStream) {
-                NSStreamStatus inputStatus = self.base64InputStream.streamStatus;
+            if (self.combinedInputStream) {
+                NSStreamStatus inputStatus = self.combinedInputStream.streamStatus;
                 if (inputStatus == NSStreamStatusClosed) {
-                    CMISLogTrace(@"Base64InputStream %@ is closed", self.base64InputStream);
+                    CMISLogTrace(@"combinedInputStream %@ is closed", self.combinedInputStream);
                 } else if (inputStatus == NSStreamStatusAtEnd){
-                    CMISLogTrace(@"Base64InputStream %@ has reached the end", self.base64InputStream);
+                    CMISLogTrace(@"combinedInputStream %@ has reached the end", self.combinedInputStream);
                 } else if (inputStatus == NSStreamStatusError){
-                    CMISLogTrace(@"Base64InputStream %@ input stream error: %@", self.base64InputStream, self.base64InputStream.streamError);
+                    CMISLogTrace(@"combinedInputStream %@ input stream error: %@", self.combinedInputStream, self.combinedInputStream.streamError);
                     [self stopSendWithStatus:@"Network read error"];
                 }
             }
@@ -350,7 +347,13 @@ totalBytesExpectedToWrite:(NSInteger)tot
                     if (-1 == rawBytesRead) {
                         [self stopSendWithStatus:@"Error while reading from source input stream"];
                     } else if (0 != rawBytesRead) {
-                        NSData *encodedBuffer = [CMISBase64Encoder dataByEncodingText:[NSData dataWithBytes:rawBuffer length:rawBytesRead]];
+                        
+                        NSData *encodedBuffer;
+                        if (self.base64Encoding) {
+                            encodedBuffer = [CMISBase64Encoder dataByEncodingText:[NSData dataWithBytes:rawBuffer length:rawBytesRead]];
+                        } else {
+                            encodedBuffer = [NSData dataWithBytes:rawBuffer length:rawBytesRead];
+                        }
                         self.dataBuffer = [NSData dataWithData:encodedBuffer];
                         self.bufferOffset = 0;
                         self.bufferLimit = encodedBuffer.length;
@@ -413,37 +416,29 @@ totalBytesExpectedToWrite:(NSInteger)tot
 
 
 #pragma private methods
-- (void)prepareXMLWithCMISProperties:(CMISProperties *)cmisProperties mimeType:(NSString *)mimeType
+
+- (void)prepareStreams
 {
     self.bufferOffset = 0;
-    CMISAtomEntryWriter *writer = [[CMISAtomEntryWriter alloc] init];
-    writer.cmisProperties = cmisProperties;
-    writer.mimeType = mimeType;
-    
-    NSString *xmlStart = [writer xmlStartElement];
-    NSString *xmlContentStart = [writer xmlContentStartElement];
     
-    NSString *start = [NSString stringWithFormat:@"%@%@", xmlStart, xmlContentStart];
-    self.streamStartData = [NSMutableData dataWithData:[start dataUsingEncoding:NSUTF8StringEncoding]];
     self.bufferLimit = self.streamStartData.length;
     self.dataBuffer = [NSData dataWithData:self.streamStartData];
     
-    NSString *xmlContentEnd = [writer xmlContentEndElement];
-    NSString *xmlProperties = [writer xmlPropertiesElements];
-    NSString *end = [NSString stringWithFormat:@"%@%@", xmlContentEnd, xmlProperties];
-    self.streamEndData = [end dataUsingEncoding:NSUTF8StringEncoding];
+    unsigned long long bytesExpected = self.bytesExpected;
+    
+    if (self.base64Encoding) {
+        // if base64 encoding is being used we need to adjust the bytesExpected
+        bytesExpected = [CMISHttpUploadRequest base64EncodedLength:self.bytesExpected];
+    }
     
-    unsigned long long encodedLength = [CMISHttpUploadRequest base64EncodedLength:self.bytesExpected];
+    unsigned long long encodedLength = bytesExpected;
     encodedLength += self.streamStartData.length;
     encodedLength += self.streamEndData.length;
-    self.encodedLength = encodedLength;
     
     // update the originally provided expected bytes with encoded length
     self.bytesExpected = encodedLength;
-}
-
-- (void)prepareStreams
-{
+    self.encodedLength = self.bytesExpected;
+    
     if (self.inputStream.streamStatus != NSStreamStatusOpen) {
         [self.inputStream open];
     }
@@ -453,7 +448,7 @@ totalBytesExpectedToWrite:(NSInteger)tot
     [NSStream createBoundInputStream:&requestInputStream outputStream:&outputStream];
     assert(requestInputStream != nil);
     assert(outputStream != nil);
-    self.base64InputStream = requestInputStream;
+    self.combinedInputStream = requestInputStream;
     self.encoderStream = outputStream;
     self.encoderStream.delegate = self;
     [self.encoderStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
@@ -498,7 +493,7 @@ totalBytesExpectedToWrite:(NSInteger)tot
         [self.encoderStream close];
         self.encoderStream = nil;
     }
-    self.base64InputStream = nil;
+    self.combinedInputStream = nil;
     if(self.inputStream != nil){
         [self.inputStream close];
         self.inputStream = nil;

Modified: chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.h
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.h?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.h (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.h Wed May 21 12:50:59 2014
@@ -38,4 +38,9 @@
           forObjectTypeId:(NSString *)objectTypeId 
           completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock;
 
+/**
+ * Converts the source to an array with elements of type CMISExtensionElement. Elements of the source with keys that are contained in the cmisKeys set set are ignored.
+ */
++ (NSArray *)convertExtensions:(NSDictionary *)source cmisKeys:(NSSet *)cmisKeys;
+
 @end

Modified: chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.m
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.m?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.m (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISObjectConverter.m Wed May 21 12:50:59 2014
@@ -26,6 +26,7 @@
 #import "CMISSession.h"
 #import "CMISDateUtil.h"
 #import "CMISConstants.h"
+#import "CMISNSDictionary+CMISUtil.h"
 
 @interface CMISObjectConverter ()
 @property (nonatomic, weak) CMISSession *session;
@@ -465,4 +466,77 @@
     }
 }
 
++ (NSArray *)convertExtensions:(NSDictionary *)source cmisKeys:(NSSet *)cmisKeys
+{
+    if (!source) {
+        return nil;
+    }
+    
+    NSMutableArray *extensions = nil; // array of CMISExtensionElement's
+    
+    for (NSString *key in source.keyEnumerator) {
+        if ([cmisKeys containsObject:key]) {
+            continue;
+        }
+        
+        if (!extensions) {
+            extensions = [[NSMutableArray alloc] init];
+        }
+        
+        id value = [source cmis_objectForKeyNotNull:key];
+        if ([value isKindOfClass:NSDictionary.class]) {
+            [extensions addObject:[[CMISExtensionElement alloc] initNodeWithName:key namespaceUri:nil attributes:nil children:[CMISObjectConverter convertExtension:value]]];
+        } else if ([value isKindOfClass:NSArray.class]) {
+            [extensions addObjectsFromArray:[CMISObjectConverter convertExtension: key fromArray:value]];
+        } else {
+            [extensions addObject:[[CMISExtensionElement alloc] initLeafWithName:key namespaceUri:nil attributes:nil value:value]];
+        }
+    }
+    return extensions;
+}
+
++ (NSArray *)convertExtension:(NSDictionary *)dictionary
+{
+    if (!dictionary) {
+        return nil;
+    }
+    
+    NSMutableArray *extensions = [[NSMutableArray alloc] init]; // array of CMISExtensionElement's
+    
+    for (NSString *key in dictionary.keyEnumerator) {
+        id value = [dictionary cmis_objectForKeyNotNull:key];
+        if ([value isKindOfClass:NSDictionary.class]) {
+            [extensions addObject:[[CMISExtensionElement alloc] initNodeWithName:key namespaceUri:nil attributes:nil children:[CMISObjectConverter convertExtension:value]]];
+        } else if ([value isKindOfClass:NSArray.class]) {
+            [extensions addObjectsFromArray:[CMISObjectConverter convertExtension: key fromArray:value]];
+        } else {
+            [extensions addObject:[[CMISExtensionElement alloc] initLeafWithName:key namespaceUri:nil attributes:nil value:value]];
+        }
+    }
+    
+    return extensions;
+}
+
++ (NSArray *)convertExtension:(NSString *)key fromArray:(NSArray *)array
+{
+    if (!array) {
+        return nil;
+    }
+    
+    NSMutableArray *extensions = [[NSMutableArray alloc] init]; // array of CMISExtensionElement's
+    
+    for (id element in array) {
+        if ([element isKindOfClass:NSDictionary.class]) {
+            [extensions addObject:[[CMISExtensionElement alloc] initNodeWithName:key namespaceUri:nil attributes:nil children:[CMISObjectConverter convertExtension:element]]];
+        } else if ([element isKindOfClass:NSArray.class]) {
+            [extensions addObjectsFromArray:[CMISObjectConverter convertExtension: key fromArray:element]];
+        } else {
+            [extensions addObject:[[CMISExtensionElement alloc] initLeafWithName:key namespaceUri:nil attributes:nil value:element]];
+        }
+    }
+    
+    return extensions;
+}
+
+
 @end

Modified: chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.h
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.h?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.h (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.h Wed May 21 12:50:59 2014
@@ -21,9 +21,23 @@
 
 
 @interface CMISURLUtil : NSObject
-/// utility method to obtain a URL string
+
+/// utility method to obtain a URL string for given parameter and string value
 + (NSString *)urlStringByAppendingParameter:(NSString *)parameterName value:(NSString *)parameterValue urlString:(NSString *)urlString;
+
+/// convenient utility method to obtain a URL string for given parameter and boolean value
++ (NSString *)urlStringByAppendingParameter:(NSString *)parameterName boolValue:(BOOL)parameterValue urlString:(NSString *)urlString;
+
+/// convenient utility method to obtain a URL string for given parameter and boolean value
++ (NSString *)urlStringByAppendingParameter:(NSString *)parameterName numberValue:(NSNumber *)parameterValue urlString:(NSString *)urlString;
+
+/// utility method to obtain a URL string by appending the given path
++ (NSString *)urlStringByAppendingPath:(NSString *)path urlString:(NSString *)urlString;
+
 /// utility method to obtain a URL string
 + (NSURL *)urlStringByAppendingParameter:(NSString *)parameterName value:(NSString *)parameterValue url:(NSURL *)url;
 
+/// utility method to encode a URL parameter value
++ (NSString *)encodeUrlParameterValue:(NSString *)value;
+
 @end
\ No newline at end of file

Modified: chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.m
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.m?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.m (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMIS/Utils/CMISURLUtil.m Wed May 21 12:50:59 2014
@@ -18,10 +18,24 @@
  */
  
 #import "CMISURLUtil.h"
+#import "CMISConstants.h"
+
+NSString * const kCMISRFC7232Reserved = @";?:@&=+$,[]";
+NSString * const kCMISRFC3986Reserved = @"!*'();:@&=+$,/?%#[]";
 
 
 @implementation CMISURLUtil
 
++ (NSString *)urlStringByAppendingParameter:(NSString *)parameterName boolValue:(BOOL)parameterValue urlString:(NSString *)urlString
+{
+    return [CMISURLUtil urlStringByAppendingParameter:parameterName value:parameterValue ? kCMISParameterValueTrue : kCMISParameterValueFalse urlString:urlString];
+}
+
++ (NSString *)urlStringByAppendingParameter:(NSString *)parameterName numberValue:(NSNumber *)parameterValue urlString:(NSString *)urlString
+{
+    return [CMISURLUtil urlStringByAppendingParameter:parameterName value:[parameterValue stringValue] urlString:urlString];
+}
+
 + (NSString *)urlStringByAppendingParameter:(NSString *)parameterName value:(NSString *)parameterValue urlString:(NSString *)urlString
 {
     if (parameterName == nil || parameterValue == nil) {
@@ -34,7 +48,9 @@
     if ([result rangeOfString:@"?"].location == NSNotFound) {
         [result appendString:@"?"];
     } else {
-        [result appendString:@"&"];
+        if([result rangeOfString:@"?"].location != result.length -1){ // Only add ampersand if there is already a parameter added
+            [result appendString:@"&"];
+        }
     }
 
     // Append param
@@ -45,9 +61,73 @@
     return result;
 }
 
++ (NSString *)urlStringByAppendingPath:(NSString *)path urlString:(NSString *)urlString
+{
+    if(!path){
+        return urlString;
+    }
+    
+    if([path rangeOfString:@"/"].location == 0) {
+        path = [path substringFromIndex:1];
+    }
+    
+    NSURL *url = [[NSURL URLWithString:urlString] URLByAppendingPathComponent:path];
+
+    // quote some additional reserved characters
+    path = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
+                                                                     (CFStringRef)url.path,
+                                                                     NULL,
+                                                                     (CFStringRef)kCMISRFC7232Reserved,
+                                                                     kCFStringEncodingUTF8));
+    
+    return [self replacePathInUrl:[url absoluteString] withPath:path];
+}
+
 + (NSURL *)urlStringByAppendingParameter:(NSString *)parameterName value:(NSString *)parameterValue url:(NSURL *)url
 {
     return [NSURL URLWithString:[CMISURLUtil urlStringByAppendingParameter:parameterName value:parameterValue urlString:[url absoluteString]]];
 }
 
++ (NSString *)encodeUrlParameterValue:(NSString *)value
+{
+    NSString *encodedValue = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
+                                                                                       (CFStringRef)value,
+                                                                                       NULL,
+                                                                                       (CFStringRef)kCMISRFC3986Reserved,
+                                                                                       kCFStringEncodingUTF8));
+    return encodedValue;
+}
+
+#pragma mark -
+#pragma mark Private helper methods
+
++ (NSString *)replacePathInUrl:(NSString *)url withPath:(NSString *)replacementPath
+{
+    NSMutableString *serverUrl = [[NSMutableString alloc] init];
+    
+    NSURL *tmp = [[NSURL alloc] initWithString:url];
+    
+    if(tmp.scheme){
+        [serverUrl appendFormat:@"%@://", tmp.scheme];
+    }
+    if(tmp.host){
+        [serverUrl appendString:tmp.host];
+    }
+    if(tmp.port){
+        [serverUrl appendFormat:@":%@", [tmp.port stringValue]];
+    }
+    if(replacementPath){
+        [serverUrl appendString:replacementPath];
+    }
+    if(tmp.query){
+        [serverUrl appendFormat:@"?%@", tmp.query];
+    }
+    
+    if(serverUrl.length == 0){ //this happens when it's not a valid url
+        [serverUrl appendString:url];
+    }
+    
+    return serverUrl;
+}
+
 @end
\ No newline at end of file

Modified: chemistry/objectivecmis/trunk/ObjectiveCMISTests/CMISBaseTest.m
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMISTests/CMISBaseTest.m?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMISTests/CMISBaseTest.m (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMISTests/CMISBaseTest.m Wed May 21 12:50:59 2014
@@ -46,7 +46,6 @@
 
     for (NSDictionary *envDict in environmentArray) {
         NSString *summary = envDict[@"summary"];
-
         NSNumber *disabled = envDict[@"disabled"];
         if ([disabled boolValue])
         {
@@ -54,30 +53,50 @@
             continue;
         }
         
-        NSString *url = envDict[@"url"];
-        NSString *repositoryId = envDict[@"repositoryId"];
-        NSString *username = envDict[@"username"];
-        NSString *password = envDict[@"password"];
+        NSString *binding = [envDict valueForKey:@"binding"];
+        NSString *url = [envDict valueForKey:@"url"];
+        NSString *repositoryId = [envDict valueForKey:@"repositoryId"];
+        NSString *username = [envDict valueForKey:@"username"];
+        NSString *password = [envDict valueForKey:@"password"];
 
-        CMISLogDebug(@">------------------- Running test against %@ -------------------<", summary);
+        // ensure there is a binding value, default to atom
+        if (binding == nil)
+        {
+            binding = @"atom";
+        }
         
         self.testCompleted = NO;
-        [self setupCmisSession:url repositoryId:repositoryId username:username password:password extraSessionParameters:extraSessionParameters completionBlock:^{
+        [self setupCmisSessionWithBinding:binding url:url repositoryId:repositoryId
+                                 username:username password:password
+                   extraSessionParameters:extraSessionParameters completionBlock:^{
             self.testCompleted = NO;
+            
+            CMISLogDebug(@">------------------- Running test against %@ -------------------<", summary);
+            
             testBlock();
         }];
-        [self waitForCompletion:90];
+        [self waitForCompletion:20];
     }
 }
 
-- (void)setupCmisSession:(NSString *)url repositoryId:(NSString *)repositoryId username:(NSString *)username
-                  password:(NSString *)password extraSessionParameters:(NSDictionary *)extraSessionParameters
-         completionBlock:(void (^)(void))completionBlock
-{
-    self.parameters = [[CMISSessionParameters alloc] initWithBindingType:CMISBindingTypeAtomPub];
+- (void)setupCmisSessionWithBinding:(NSString *)binding url:(NSString *)url repositoryId:(NSString *)repositoryId
+                           username:(NSString *)username password:(NSString *)password
+             extraSessionParameters:(NSDictionary *)extraSessionParameters
+                    completionBlock:(void (^)(void))completionBlock
+{
+    if ([binding isEqualToString:@"browser"])
+    {
+        self.parameters = [[CMISSessionParameters alloc] initWithBindingType:CMISBindingTypeBrowser];
+        self.parameters.browserUrl = [NSURL URLWithString:url];
+    }
+    else
+    {
+        self.parameters = [[CMISSessionParameters alloc] initWithBindingType:CMISBindingTypeAtomPub];
+        self.parameters.atomPubUrl = [NSURL URLWithString:url];
+    }
+    
     self.parameters.username = username;
     self.parameters.password = password;
-    self.parameters.atomPubUrl = [NSURL URLWithString:url];
     self.parameters.repositoryId = repositoryId;
 
     // Extra cmis params could be provided as method parameter
@@ -133,6 +152,7 @@
         CMISDocument *document = (CMISDocument *)object;
         XCTAssertNotNil(document, @"Did not find test document for versioning test");
         XCTAssertTrue(document.isLatestVersion, @"Should have 'true' for the property 'isLatestVersion");
+        //XCTAssertFalse(document.isLatestMajorVersion, @"Should have 'false' for the property 'isLatestMajorVersion"); // the latest version is a minor one
         XCTAssertFalse(document.isMajorVersion, @"Should have 'false' for the property 'isMajorVersion");
         
         completionBlock(document);

Modified: chemistry/objectivecmis/trunk/ObjectiveCMISTests/ObjectiveCMISTests.m
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMISTests/ObjectiveCMISTests.m?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMISTests/ObjectiveCMISTests.m (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMISTests/ObjectiveCMISTests.m Wed May 21 12:50:59 2014
@@ -34,14 +34,15 @@
 #import "CMISPagedResult.h"
 #import "CMISRenditionData.h"
 #import "CMISRendition.h"
-#import "CMISAllowableActionsParser.h"
 #import "CMISAtomFeedParser.h"
-#import "CMISServiceDocumentParser.h"
-#import "CMISWorkspace.h"
+#import "CMISAtomPubServiceDocumentParser.h"
+#import "CMISAtomWorkspace.h"
 #import "CMISRequest.h"
 #import "CMISErrors.h"
 #import "CMISDateUtil.h"
 #import "CMISLog.h"
+#import "CMISURLUtil.h"
+#import "CMISMimeHelper.h"
 
 @interface ObjectiveCMISTests ()
 
@@ -140,8 +141,14 @@
 - (void)testAuthenticateWithInvalidCredentials
 {
     [self runTest:^ {
-        CMISSessionParameters *bogusParams = [[CMISSessionParameters alloc] initWithBindingType:CMISBindingTypeAtomPub];
-        bogusParams.atomPubUrl = self.parameters.atomPubUrl;
+        CMISSessionParameters *bogusParams = nil;
+        if (self.parameters.bindingType == CMISBindingTypeAtomPub) {
+            bogusParams = [[CMISSessionParameters alloc] initWithBindingType:CMISBindingTypeAtomPub];
+            bogusParams.atomPubUrl = self.parameters.atomPubUrl;
+        } else {
+            bogusParams = [[CMISSessionParameters alloc] initWithBindingType:CMISBindingTypeBrowser];
+            bogusParams.browserUrl = self.parameters.browserUrl;
+        }
         bogusParams.repositoryId = self.parameters.repositoryId;
         bogusParams.username = @"bogus";
         bogusParams.password = @"sugob";
@@ -168,8 +175,9 @@
         XCTAssertNotNil(repoInfo, @"repoInfo object should not be nil");
 
         // check the repository info is what we expect
-        XCTAssertTrue(repoInfo.productVersion.length > 0, @"Product Version should not be zero-length");
-        XCTAssertTrue([repoInfo.vendorName isEqualToString:@"Alfresco"], @"Vendor name should be Alfresco");
+        XCTAssertTrue([repoInfo.productVersion rangeOfString:@"4."].length > 0, @"Product Version should be 4.x.x, but was %@", repoInfo.productVersion);
+        XCTAssertTrue([repoInfo.productName hasPrefix:@"Alfresco"], @"Product name should start with Alfresco, but was %@", repoInfo.productName);
+        XCTAssertTrue([repoInfo.vendorName isEqualToString:@"Alfresco"], @"Vendor name should be Alfresco, but was %@", repoInfo.vendorName);
 
         // retrieve the root folder
         [self.session retrieveRootFolderWithCompletionBlock:^(CMISFolder *rootFolder, NSError *error) {
@@ -190,6 +198,52 @@
             NSDate *modifiedDate = rootFolder.lastModificationDate;
             XCTAssertNotNil(modifiedDate, @"modified date should not be nil");
             
+            // test various aspects of type definition
+            CMISTypeDefinition *typeDef = rootFolder.typeDefinition;
+            XCTAssertNotNil(typeDef, @"Expected the type definition to be present");
+            XCTAssertTrue([typeDef.identifier isEqualToString:@"cmis:folder"], @"Expected typeDef.identifier to be cmis:folder but it was %@", typeDef.identifier);
+            XCTAssertTrue([typeDef.localName isEqualToString:@"folder"], @"Expected typeDef.localName to be folder but it was %@", typeDef.localName);
+            XCTAssertTrue([typeDef.queryName isEqualToString:@"cmis:folder"], @"Expected typeDef.queryName to be cmis:folder but it was %@", typeDef.queryName);
+            XCTAssertTrue(typeDef.baseTypeId == CMISBaseTypeFolder, @"Expected baseTypeId to be cmis:folder");
+            XCTAssertTrue(typeDef.creatable, @"Expected creatable to be true");
+            XCTAssertTrue(typeDef.fileable, @"Expected fileable to be true");
+            XCTAssertTrue(typeDef.queryable, @"Expected queryable to be true");
+            XCTAssertTrue(typeDef.fullTextIndexed, @"Expected fullTextIndexed to be true");
+            XCTAssertTrue(typeDef.includedInSupertypeQuery, @"Expected includedInSupertypeQuery to be true");
+            XCTAssertTrue(typeDef.controllableAcl, @"Expected controllableAcl to be true");
+            XCTAssertFalse(typeDef.controllablePolicy, @"Expected controllablePolicy to be false");
+            
+            CMISPropertyDefinition *objectTypeIdDef = typeDef.propertyDefinitions[@"cmis:objectTypeId"];
+            XCTAssertNotNil(objectTypeIdDef, @"Expected to find cmis:objectTypeId property definition");
+            XCTAssertTrue([objectTypeIdDef.identifier isEqualToString:@"cmis:objectTypeId"],
+                          @"Expected objectTypeIdDef.id to be cmis:objectTypeId but it was %@", objectTypeIdDef.identifier);
+            XCTAssertTrue([objectTypeIdDef.localName isEqualToString:@"objectTypeId"],
+                          @"Expected objectTypeIdDef.localName to be objectTypeId but it was %@", objectTypeIdDef.localName);
+            XCTAssertTrue(objectTypeIdDef.propertyType == CMISPropertyTypeId, @"Expected objectTypeId type to be id");
+            XCTAssertTrue(objectTypeIdDef.cardinality == CMISCardinalitySingle, @"Expected objectTypeId cardinality to be single");
+            XCTAssertTrue(objectTypeIdDef.updatability == CMISUpdatabilityOnCreate, @"Expected objectTypeId updatability to be oncreate");
+            XCTAssertTrue(objectTypeIdDef.required, @"Expected objectTypeId to be required");
+            
+            // test secondary type id when using the 1.1 bindings
+            CMISPropertyDefinition *secondaryTypeIdDef = typeDef.propertyDefinitions[@"cmis:secondaryObjectTypeIds"];
+            if (secondaryTypeIdDef != nil)
+            {
+                XCTAssertNotNil(secondaryTypeIdDef, @"Expected to find cmis:secondaryObjectTypeIds property definition");
+                XCTAssertTrue([secondaryTypeIdDef.identifier isEqualToString:@"cmis:secondaryObjectTypeIds"],
+                              @"Expected secondaryTypeIdDef.id to be cmis:secondaryObjectTypeIds but it was %@", secondaryTypeIdDef.identifier);
+                XCTAssertTrue([secondaryTypeIdDef.localName isEqualToString:@"secondaryObjectTypeIds"],
+                              @"Expected objectTypeIdDef.localName to be secondaryObjectTypeIds but it was %@", secondaryTypeIdDef.localName);
+                XCTAssertTrue(secondaryTypeIdDef.propertyType == CMISPropertyTypeId, @"Expected secondaryTypeIdDef type to be id");
+                XCTAssertTrue(secondaryTypeIdDef.cardinality == CMISCardinalityMulti, @"Expected secondaryTypeIdDef cardinality to be multi");
+                XCTAssertTrue(secondaryTypeIdDef.updatability == CMISUpdatabilityReadWrite, @"Expected secondaryTypeIdDef updatability to be readwrite");
+                XCTAssertFalse(secondaryTypeIdDef.required, @"Expected secondaryTypeIdDef to be optional");
+            }
+            
+            // test some other random properties
+            CMISPropertyDefinition *creationDateDef = typeDef.propertyDefinitions[@"cmis:creationDate"];
+            XCTAssertTrue(creationDateDef.propertyType == CMISPropertyTypeDateTime, @"Expected creationDateDef type to be datetime");
+            XCTAssertTrue(creationDateDef.updatability == CMISUpdatabilityReadOnly, @"Expected creationDateDef updatability to be readonly");
+            
             // retrieve the children of the root folder, there should be more than 10!
             [rootFolder retrieveChildrenWithCompletionBlock:^(CMISPagedResult *pagedResult, NSError *error) {
                 XCTAssertNil(error, @"Got error while retrieving children: %@", [error description]);
@@ -242,22 +296,22 @@
                     }
                     
                     
-                    // Bug on Alfresco server. Uncomment when fixed.
                     // Fetch third page, just to be sure
-                    //    CMISPagedResult *thirdPageResult = [secondPageResult fetchNextPageAndReturnError:&error];
-                    //    STAssertNil(error, @"Got error while retrieving children: %@", [error description]);
-                    //    STAssertTrue(thirdPageResult.hasMoreItems, @"There should still be more children");
-                    //    STAssertTrue(thirdPageResult.numItems > 6, @"The test repository should have more than 6 objects");
-                    //    STAssertTrue(thirdPageResult.resultArray.count == 2, @"Expected 2 children in the page, but got %d", thirdPageResult.resultArray.count);
-                    //
-                    //    // Verify if no double object ids were found
-                    //    for (CMISObject *object in thirdPageResult.resultArray)
-                    //    {
-                    //        STAssertTrue(![objectIds containsObject:object.identifier], @"Object was already returned in a previous page. This is a serious impl bug!");
-                    //        [objectIds addObject:object.identifier];
-                    //    }
+                    [secondPageResult fetchNextPageWithCompletionBlock:^(CMISPagedResult *thirdPageResult, NSError *error) {
+                        XCTAssertNil(error, @"Got error while retrieving children: %@", [error description]);
+                        XCTAssertTrue(thirdPageResult.hasMoreItems, @"There should still be more children");
+                        XCTAssertTrue(thirdPageResult.numItems > 6, @"The test repository should have more than 6 objects");
+                        XCTAssertTrue(thirdPageResult.resultArray.count == 2, @"Expected 2 children in the page, but got %lu", (unsigned long)thirdPageResult.resultArray.count);
                     
-                    self.testCompleted = YES;
+                        // Verify if no double object ids were found
+                        for (CMISObject *object in thirdPageResult.resultArray)
+                        {
+                            XCTAssertTrue(![objectIds containsObject:object.identifier], @"Object was already returned in a previous page. This is a serious impl bug!");
+                            [objectIds addObject:object.identifier];
+                        }
+                        
+                        self.testCompleted = YES;
+                    }];
                 }];
             }];
         }];
@@ -284,8 +338,8 @@
             XCTAssertNotNil(document.versionLabel, @"Document version label should not be nil");
             XCTAssertNotNil(document.versionSeriesId, @"Document version series id should not be nil");
             XCTAssertTrue(document.isLatestVersion, @"Document should be latest version");
-            //XCTAssertTrue(document.isLatestMajorVersion, @"Document should be latest major version");
-            XCTAssertFalse(document.isMajorVersion, @"Document should be major version");
+            //XCTAssertFalse(document.isLatestMajorVersion, @"Document should be latest major version");
+            XCTAssertFalse(document.isMajorVersion, @"Document should not be major version");
             
             XCTAssertNotNil(document.contentStreamId, @"Document content stream id should not be nil");
             XCTAssertNotNil(document.contentStreamFileName, @"Document content stream file name should not be nil");
@@ -338,7 +392,11 @@
                     }
                 }
                 
-                XCTAssertNotNil(randomDoc, @"Can only continue test if test folder contains at least one document");
+                if(!randomDoc) { // stopping test here or else it would run until the test timeout is reached
+                    XCTAssertNotNil(randomDoc, @"Can only continue test if test folder contains at least one document");
+                    self.testCompleted = YES;
+                    return;
+                }
                 CMISLogDebug(@"Fetching content stream for document %@", randomDoc.name);
                 
                 // Writing content of CMIS document to local file
@@ -417,44 +475,44 @@
         
         // Upload test file
         self.request = [self.session createDocumentFromFilePath:filePath
-                                        mimeType:@"application/pdf"
-                                      properties:documentProperties
-                                        inFolder:self.rootFolder.identifier
-                                 completionBlock: ^ (NSString *newObjectId, NSError *error) {
-                                     
-                                     XCTAssertNotNil(error, @"Failed to cancel upload");
-                                     XCTAssertTrue(error.code == kCMISErrorCodeCancelled, @"Expected error code to be 6 (kCMISErrorCodeCancelled) but it was %ld", (long)error.code);
-                                     XCTAssertNil(newObjectId, @"Did not expect to recieve a new object id");
-                                     
-                                     // ensure the object was not created on the server
-                                     NSString *path = [NSString stringWithFormat:@"/%@", documentName];
-                                     [self.session retrieveObjectByPath:path completionBlock:^(CMISObject *object, NSError *error) {
-                                         XCTAssertNotNil(error, @"Expected to get an error when attempting to retrieve cancelled upload");
-                                         XCTAssertTrue(error.code == kCMISErrorCodeObjectNotFound, @"Expected error code to be 257 (kCMISErrorCodeObjectNotFound) but it was %ld", (long)error.code);
-                                         XCTAssertNil(object, @"Did not expect the object to be created on the server");
-                                         
-                                         if (object != nil)
-                                         {
-                                             // if object was created, cleanup
-                                             [self deleteDocumentAndVerify:(CMISDocument *)object completionBlock:^{
-                                                 self.testCompleted = YES;
-                                             }];
-                                         }
-                                         else
-                                         {
-                                             self.testCompleted = YES;
-                                         }
-                                     }];
-                                 }
-                                   progressBlock: ^ (unsigned long long uploadedBytes, unsigned long long totalBytes) {
-                                       CMISLogDebug(@"upload progress %i/%i", uploadedBytes, totalBytes);
-                                       if (uploadedBytes > 0) {
-                                           // as soon as some data was uploaded cancel the request
-                                           [self.request cancel];
-                                           CMISLogDebug(@"create cancelled");
-                                           self.request = nil;
-                                       }
-                                   }];
+                                                       mimeType:@"application/pdf"
+                                                     properties:documentProperties
+                                                       inFolder:self.rootFolder.identifier
+                                                completionBlock: ^ (NSString *newObjectId, NSError *error) {
+                                                    
+                                                    XCTAssertNotNil(error, @"Failed to cancel upload");
+                                                    XCTAssertTrue(error.code == kCMISErrorCodeCancelled, @"Expected error code to be 6 (kCMISErrorCodeCancelled) but it was %ld", (long)error.code);
+                                                    XCTAssertNil(newObjectId, @"Did not expect to recieve a new object id");
+                                                    
+                                                    // ensure the object was not created on the server
+                                                    NSString *path = [NSString stringWithFormat:@"/%@", documentName];
+                                                    [self.session retrieveObjectByPath:path completionBlock:^(CMISObject *object, NSError *error) {
+                                                        XCTAssertNotNil(error, @"Expected to get an error when attempting to retrieve cancelled upload");
+                                                        XCTAssertTrue(error.code == kCMISErrorCodeObjectNotFound, @"Expected error code to be 257 (kCMISErrorCodeObjectNotFound) but it was %ld", (long)error.code);
+                                                        XCTAssertNil(object, @"Did not expect the object to be created on the server");
+                                                        
+                                                        if (object != nil)
+                                                        {
+                                                            // if object was created, cleanup
+                                                            [self deleteDocumentAndVerify:(CMISDocument *)object completionBlock:^{
+                                                                self.testCompleted = YES;
+                                                            }];
+                                                        }
+                                                        else
+                                                        {
+                                                            self.testCompleted = YES;
+                                                        }
+                                                    }];
+                                                }
+                                                  progressBlock: ^ (unsigned long long uploadedBytes, unsigned long long totalBytes) {
+                                                      CMISLogDebug(@"upload progress %i/%i", uploadedBytes, totalBytes);
+                                                      if (uploadedBytes > 0) {
+                                                          // as soon as some data was uploaded cancel the request
+                                                          [self.request cancel];
+                                                          CMISLogDebug(@"create cancelled");
+                                                          self.request = nil;
+                                                      }
+                                                  }];
     }];
 }
 
@@ -593,9 +651,7 @@
                 XCTAssertNil(error, @"Got error while creating document: %@", [error description]);
                 self.testCompleted = YES;
             }
-        } progressBlock:^(unsigned long long bytesUploaded, unsigned long long total){
-            CMISLogDebug(@"upload progress %i/%i", bytesUploaded, total);
-        }];
+        } progressBlock:^(unsigned long long bytesUploaded, unsigned long long total){}];
         
     }];
 }
@@ -676,7 +732,6 @@
                }
                progressBlock:^(unsigned long long bytesUploaded, unsigned long long bytesTotal)
                {
-                   CMISLogDebug(@"upload progress %i/%i", bytesUploaded, bytesTotal);
                    XCTAssertTrue((long long)bytesUploaded > previousBytesUploaded, @"No progress was made");
                    previousBytesUploaded = bytesUploaded;
                }];
@@ -743,6 +798,7 @@
                                                  continueOnFailure:YES
                                                    completionBlock:^(NSArray *failedObjects, NSError *error) {
                                                        XCTAssertNil(error, @"Error while move test folders and document: %@", [error description]);
+                                                       XCTAssertTrue(failedObjects.count == 0, @"some objects could not be deleted");
                                                        
                                                        self.testCompleted = YES;
                                                    }];
@@ -1349,8 +1405,8 @@
              XCTAssertTrue(typeDefinition.baseTypeId == CMISBaseTypeDocument, @"Unexpected base type id");
              XCTAssertNotNil(typeDefinition.description, @"Type description should not be nil");
              XCTAssertNotNil(typeDefinition.displayName, @"Type displayName should not be nil");
-             XCTAssertNotNil(typeDefinition.id, @"Type id should not be nil");
-             XCTAssertTrue([typeDefinition.id isEqualToString:@"cmis:document"], @"Wrong id for type");
+             XCTAssertNotNil(typeDefinition.identifier, @"Type id should not be nil");
+             XCTAssertTrue([typeDefinition.identifier isEqualToString:@"cmis:document"], @"Wrong id for type");
              XCTAssertNotNil(typeDefinition.localName, @"Type local name should not be nil");
              XCTAssertNotNil(typeDefinition.localNameSpace, @"Type local namespace should not be nil");
              XCTAssertNotNil(typeDefinition.queryName, @"Type query name should not be nil");
@@ -1362,7 +1418,7 @@
                  CMISPropertyDefinition *propertyDefinition = [typeDefinition.propertyDefinitions objectForKey:key];
                  XCTAssertNotNil(propertyDefinition.description, @"Property definition description should not be nil");
                  XCTAssertNotNil(propertyDefinition.displayName, @"Property definition display name should not be nil");
-                 XCTAssertNotNil(propertyDefinition.id, @"Property definition id should not be nil");
+                 XCTAssertNotNil(propertyDefinition.identifier, @"Property definition id should not be nil");
                  XCTAssertNotNil(propertyDefinition.localName, @"Property definition local name should not be nil");
                  XCTAssertNotNil(propertyDefinition.localNamespace, @"Property definition local namespace should not be nil");
                  XCTAssertNotNil(propertyDefinition.queryName, @"Property definition query name should not be nil");
@@ -1666,11 +1722,11 @@
     XCTAssertNotNil(atomData, @"AtomPubServiceDocument.xml is missing from the test target!");
     
     NSError *error = nil;
-    CMISServiceDocumentParser *serviceDocParser = [[CMISServiceDocumentParser alloc] initWithData:atomData];
+    CMISAtomPubServiceDocumentParser *serviceDocParser = [[CMISAtomPubServiceDocumentParser alloc] initWithData:atomData];
     XCTAssertTrue([serviceDocParser parseAndReturnError:&error], @"Failed to parse AtomPubServiceDocument.xml");
     
     NSArray *workspaces = [serviceDocParser workspaces];
-    CMISWorkspace *workspace = [workspaces objectAtIndex:0];
+    CMISAtomWorkspace *workspace = [workspaces objectAtIndex:0];
     CMISRepositoryInfo *repoInfo = workspace.repositoryInfo;
     
     XCTAssertTrue(repoInfo.extensions.count == 2, @"Expected 2 extension elements, but found %lu", (unsigned long)repoInfo.extensions.count);
@@ -2051,4 +2107,92 @@
     }];
 }
 
+- (void)testUrlUtilAppendParameter
+{
+    NSString *path;
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"param1" value:@"value1" urlString:@"scheme://host:12345/path?"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path?param1=value1", @"expected url with with one parameter and it's value");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"param1" value:@"value1" urlString:@"scheme://host:12345/path"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path?param1=value1", @"expected url with with one parameter and it's value");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"param2" value:@"value2" urlString:@"scheme://host:12345/path?param1=value1"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path?param1=value1&param2=value2", @"expected url with with two parameters plus value");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"umlautParam" value:@"välüe1" urlString:@"scheme://host:12345/path"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path?umlautParam=v%C3%A4l%C3%BCe1", @"expected url with with encoded value");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:nil value:@"paramIsNil" urlString:@"scheme://host:12345/path"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path", @"expected url not to be modified as parameter is nil");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"valueIsNil" value:nil urlString:@"scheme://host:12345/path"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path", @"expected url not to be modified as value is nil");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"param1" value:@"value1" urlString:@"scheme://host/"];
+    XCTAssertEqualObjects(path, @"scheme://host/?param1=value1", @"expected url (no port) with with one parameter and it's value");
+    
+    path = [CMISURLUtil urlStringByAppendingParameter:@"param1" value:@"value1" urlString:@"https://example.com:12345/path1/path2"];
+    XCTAssertEqualObjects(path, @"https://example.com:12345/path1/path2?param1=value1", @"expected url with with one parameter and it's value");
+}
+
+- (void)testUrlUtilAppendPath
+{
+    NSString *path;
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"aPath" urlString:@"scheme://host:12345?"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/aPath?", @"expected url with path");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"subPath" urlString:@"scheme://host:12345/path?"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path/subPath?", @"expected url with sub path component");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"subPath" urlString:@"scheme://host:12345/path"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path/subPath", @"expected url with sub path component");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"subPath" urlString:@"scheme://host:12345/path/"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path/subPath", @"expected url with sub path component");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"subPath" urlString:@"scheme://host:12345/path?parm1=value1"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path/subPath?parm1=value1", @"expected url with sub path component, parmater and it's value");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"subPath" urlString:@"scheme://host:12345/path?parm1=value1&param2=value2"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/path/subPath?parm1=value1&param2=value2", @"expected url with sub path component, multiple parmaters and their values");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"/aPath" urlString:@"scheme://host:12345/test"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/test/aPath", @"expected url with sub path component");
+    
+    path = [CMISURLUtil urlStringByAppendingPath:@"/aPath" urlString:@"scheme://host:12345/test/"];
+    XCTAssertEqualObjects(path, @"scheme://host:12345/test/aPath", @"expected url with sub path component");
+    
+    // multi-segment path with special chars, space turns into %20
+    path = [CMISURLUtil urlStringByAppendingPath:@"path/caf\u00e9 d@d" urlString:@"http://host/test/"];
+    XCTAssertEqualObjects(path, @"http://host/test/path/caf%C3%A9%20d%40d", @"expected url with encoded path component");
+    NSLog(@"%@", path);
+}
+
+- (void)testEncodeContentDisposition
+{
+    XCTAssertEqualObjects(@"inline; filename=foo.bar", [CMISMimeHelper encodeContentDisposition:@"inline" fileName:@"foo.bar"], @"wrong encoded content disposition");
+    XCTAssertEqualObjects(@"attachment; filename=foo.bar", [CMISMimeHelper encodeContentDisposition:nil fileName:@"foo.bar"], @"wrong encoded content disposition");
+    XCTAssertEqualObjects(@"attachment; filename*=UTF-8''caf%C3%A9.pdf", [CMISMimeHelper encodeContentDisposition:nil fileName:@"caf\u00e9.pdf"], @"wrong encoded content disposition");
+
+    // TODO how to add those unicode control characters directly into the string?
+    uint codeValue1;
+    [[NSScanner scannerWithString:@"0x0081"] scanHexInt:&codeValue1];
+    uint codeValue2;
+    [[NSScanner scannerWithString:@"0x0082"] scanHexInt:&codeValue2];
+    NSString *fileName = [NSString stringWithFormat:@" '*%% abc %C%C\r\n\t", (unichar)codeValue1, (unichar)codeValue2];
+    XCTAssertEqualObjects(@"attachment; filename*=UTF-8''%20%27%2A%25%20abc%20%C2%81%C2%82%0D%0A%09", [CMISMimeHelper encodeContentDisposition:nil fileName:fileName], @"wrong encoded content disposition");
+}
+
+- (void)testEncodeUrlParameterValue
+{
+    XCTAssertEqualObjects(@"test%20%2B%20%2Fvalue%20%26%20", [CMISURLUtil encodeUrlParameterValue:@"test + /value & "], @"wrong encoded url parameter value");
+    XCTAssertEqualObjects(@"%20%25%20%22%20", [CMISURLUtil encodeUrlParameterValue:@" % \" "], @"wrong encoded url parameter value");
+    XCTAssertEqualObjects(@"%20%60~%21%40%23%24%25%5E%26%2A%28%29_%2B-%3D%7B%7D%5B%5D%7C%5C%3A%3B%22%27%3C%2C%3E.%3F%2FAZaz", [CMISURLUtil encodeUrlParameterValue:@" `~!@#$%^&*()_+-={}[]|\\:;\"'<,>.?/AZaz"], @"wrong encoded url parameter value");
+    XCTAssertEqualObjects(@"%E5%BD%BC%E5%BE%97", [CMISURLUtil encodeUrlParameterValue:@"彼得"], @"wrong encoded url parameter value");
+    
+    XCTAssertEqualObjects(@"%C3%BC%C3%A4%C3%B6%C3%9C%C3%84%C3%96%C3%A9%C4%9F", [CMISURLUtil encodeUrlParameterValue:@"üäöÜÄÖéğ"], @"wrong encoded url parameter value");
+}
+
 @end

Modified: chemistry/objectivecmis/trunk/ObjectiveCMISTests/env-cfg.plist
URL: http://svn.apache.org/viewvc/chemistry/objectivecmis/trunk/ObjectiveCMISTests/env-cfg.plist?rev=1596563&r1=1596562&r2=1596563&view=diff
==============================================================================
--- chemistry/objectivecmis/trunk/ObjectiveCMISTests/env-cfg.plist (original)
+++ chemistry/objectivecmis/trunk/ObjectiveCMISTests/env-cfg.plist Wed May 21 12:50:59 2014
@@ -5,8 +5,8 @@
 	<key>environments</key>
 	<array>
 		<dict>
-            <key>disabled</key>
-			<true/>
+			<key>disabled</key>
+			<false/>
 			<key>summary</key>
 			<string>Alfresco v4.0.0 Enterprise. Legacy (Webscript)</string>
 			<key>username</key>
@@ -19,8 +19,8 @@
 			<string>368eca28-be2b-4a8d-8bbb-1d7997af7930</string>
 		</dict>
 		<dict>
-            <key>disabled</key>
-			<true/>
+			<key>disabled</key>
+			<false/>
 			<key>summary</key>
 			<string>Alfresco v4.0.0 Enterprise. OpenCMIS AtomPub 1.0</string>
 			<key>username</key>
@@ -33,6 +33,8 @@
 			<string>368eca28-be2b-4a8d-8bbb-1d7997af7930</string>
 		</dict>
 		<dict>
+			<key>disabled</key>
+			<false/>
 			<key>summary</key>
 			<string>Alfresco v4.2.0 Enterprise. OpenCMIS (PublicAPI) AtomPub 1.0</string>
 			<key>username</key>
@@ -44,6 +46,22 @@
 			<key>repositoryId</key>
 			<string>-default-</string>
 		</dict>
+		<dict>
+			<key>disabled</key>
+			<false/>
+			<key>summary</key>
+			<string>Alfresco v4.2.0 Enterprise. OpenCMIS (PublicAPI) Browser 1.1</string>
+			<key>binding</key>
+			<string>browser</string>
+			<key>username</key>
+			<string>cmis</string>
+			<key>password</key>
+			<string>unittest</string>
+			<key>url</key>
+			<string>http://ec2-54-195-83-189.eu-west-1.compute.amazonaws.com/alfresco/api/-default-/public/cmis/versions/1.1/browser</string>
+			<key>repositoryId</key>
+			<string>-default-</string>
+		</dict>
 	</array>
 </dict>
 </plist>