blob: 1d700da7384dc8b734145ba8a8ffef5d5ce86611 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CMISObjectConverter.h"
#import "CMISDocument.h"
#import "CMISFolder.h"
#import "CMISTypeDefinition.h"
#import "CMISErrors.h"
#import "CMISPropertyDefinition.h"
#import "CMISSession.h"
#import "CMISDateUtil.h"
#import "CMISConstants.h"
#import "CMISDictionaryUtil.h"
@interface CMISObjectConverter ()
@property (nonatomic, weak) CMISSession *session;
@end
@implementation CMISObjectConverter
- (id)initWithSession:(CMISSession *)session
{
self = [super init];
if (self) {
self.session = session;
}
return self;
}
- (void)convertObject:(CMISObjectData *)objectData completionBlock:(void (^)(CMISObject *object, NSError *error))completionBlock
{
CMISObject *object = nil;
if (objectData.baseType == CMISBaseTypeDocument) {
object = [[CMISDocument alloc] initWithObjectData:objectData session:self.session];
} else if (objectData.baseType == CMISBaseTypeFolder) {
object = [[CMISFolder alloc] initWithObjectData:objectData session:self.session];
}
[object fetchTypeDefinitionWithCompletionBlock:^(NSError *error) {
completionBlock(object, error);
}];
}
- (void)internalConvertObject:(NSArray *)objectDatas position:(NSInteger)position completionBlock:(void (^)(NSMutableArray *objects, NSError *error))completionBlock
{
[self convertObject:[objectDatas objectAtIndex:position]
completionBlock:^(CMISObject *object, NSError *error) {
if(error){
completionBlock(nil, error);
} else {
if (position == 0) {
NSMutableArray *objects = [[NSMutableArray alloc] initWithCapacity:objectDatas.count];
[objects addObject:object];
completionBlock(objects, error);
} else {
[self internalConvertObject:objectDatas position:(position - 1) completionBlock:^(NSMutableArray *objects, NSError *error) {
[objects addObject:object];
completionBlock(objects, error);
}];
}
}
}];
}
- (void)convertObjects:(NSArray *)objectDatas completionBlock:(void (^)(NSArray *objects, NSError *error))completionBlock
{
if (objectDatas.count > 0) {
[self internalConvertObject:objectDatas
position:(objectDatas.count - 1) // start recursion with last item
completionBlock:^(NSMutableArray *objects, NSError *error) {
completionBlock(objects, error);
}];
} else {
completionBlock([[NSArray alloc] init], nil);
}
}
- (void)convertProperties:(NSDictionary *)properties
forObjectTypeId:(NSString *)objectTypeId
completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock
{
[self internalNormalConvertProperties:properties objectTypeId:objectTypeId completionBlock:completionBlock];
}
- (void)internalNormalConvertProperties:(NSDictionary *)properties
typeDefinition:(CMISTypeDefinition *)typeDefinition
completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock
{
NSArray *typeDefinitions = nil;
if (typeDefinition) {
typeDefinitions = [NSArray arrayWithObject:typeDefinition];
}
[self internalNormalConvertProperties:properties typeDefinitions:typeDefinitions completionBlock:completionBlock];
}
- (void)internalNormalConvertProperties:(NSDictionary *)properties
typeDefinitions:(NSArray *)typeDefinitions
completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock
{
CMISProperties *convertedProperties = [[CMISProperties alloc] init];
for (NSString *propertyId in properties) {
id propertyValue = [properties objectForKey:propertyId];
// If the value is already a CMISPropertyData, we don't need to do anything
if ([propertyValue isKindOfClass:[CMISPropertyData class]]) {
[convertedProperties addProperty:(CMISPropertyData *)propertyValue];
} else {
// Convert to CMISPropertyData based on the string
CMISPropertyDefinition *propertyDefinition = [self propertyDefinitionFromTypeDefinitions:typeDefinitions propertyId:propertyId];
if (propertyDefinition == nil) {
NSError *error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeInvalidArgument
detailedDescription:[NSString stringWithFormat:@"Invalid property '%@' for this object type", propertyId]];
completionBlock(nil, error);
return;
}
Class expectedType = nil;
BOOL validType = YES;
if (propertyValue == [NSNull null]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:nil type:propertyDefinition.propertyType]];
} else {
switch (propertyDefinition.propertyType) {
case(CMISPropertyTypeString): {
expectedType = [NSString class];
if ([propertyValue isKindOfClass:expectedType]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId stringValue:propertyValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeBoolean): {
expectedType = [NSNumber class];
if ([propertyValue isKindOfClass:expectedType]) {
BOOL boolValue = ((NSNumber *) propertyValue).boolValue;
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId boolValue:boolValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeInteger): {
expectedType = [NSNumber class];
if ([propertyValue isKindOfClass:expectedType]) {
NSInteger intValue = ((NSNumber *) propertyValue).integerValue;
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId integerValue:intValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeDecimal): {
expectedType = [NSNumber class];
if ([propertyValue isKindOfClass:expectedType]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId decimalValue:propertyValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeId): {
expectedType = [NSString class];
if ([propertyValue isKindOfClass:expectedType]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId idValue:propertyValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeDateTime): {
if ([propertyValue isKindOfClass:[NSString class]]) {
propertyValue = [CMISDateUtil dateFromString:propertyValue];
}
expectedType = [NSDate class];
if ([propertyValue isKindOfClass:expectedType]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId dateTimeValue:propertyValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (__strong id propertyValueItemValue in propertyValue) {
if ([propertyValueItemValue isKindOfClass:[NSString class]]) {
propertyValueItemValue = [CMISDateUtil dateFromString:propertyValueItemValue];
}
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeUri): {
if ([propertyValue isKindOfClass:[NSString class]]) {
propertyValue = [NSURL URLWithString:propertyValue];
}
expectedType = [NSURL class];
if ([propertyValue isKindOfClass:expectedType]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId uriValue:propertyValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (__strong id propertyValueItemValue in propertyValue) {
if ([propertyValueItemValue isKindOfClass:[NSString class]]) {
propertyValueItemValue = [NSURL URLWithString:propertyValueItemValue];
}
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
case(CMISPropertyTypeHtml): {
expectedType = [NSString class];
if ([propertyValue isKindOfClass:expectedType]) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId htmlValue:propertyValue]];
} else if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:expectedType]) {
validType = NO;
break;
}
}
if (validType) {
[convertedProperties addProperty:[CMISPropertyData createPropertyForId:propertyId arrayValue:propertyValue type:propertyDefinition.propertyType]];
}
} else {
validType = NO;
}
break;
}
default: {
NSError *error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeInvalidArgument
detailedDescription:[NSString stringWithFormat:@"Unsupported: cannot convert property type %li", (long)propertyDefinition.propertyType]];
completionBlock(nil, error);
return;
}
}
}
if (!validType) {
NSError *error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeInvalidArgument
detailedDescription:[NSString stringWithFormat:@"Property value for %@ should be of type '%@'", propertyId, expectedType]];
completionBlock(nil, error);
return;
}
}
}
completionBlock(convertedProperties, nil);
}
-(CMISPropertyDefinition*)propertyDefinitionFromTypeDefinitions:(NSArray *)typeDefinitions propertyId:(NSString*)propertyId
{
for (CMISTypeDefinition* typeDefinition in typeDefinitions) {
CMISPropertyDefinition *propertyDefinition = [typeDefinition propertyDefinitionForId:propertyId];
if (propertyDefinition) {
return propertyDefinition;
}
}
return nil;
}
- (void)internalNormalConvertProperties:(NSDictionary *)properties
objectTypeId:(NSString *)objectTypeId
completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock
{
// Validate params
if (!properties) {
completionBlock(nil, nil);
return;
}
BOOL onlyPropertyData = YES;
for (id propertyValue in properties.objectEnumerator) {
if (![propertyValue isKindOfClass:[CMISPropertyData class]]) {
if ([propertyValue isKindOfClass:[NSArray class]]) {
for (id propertyValueItemValue in propertyValue) {
if (![propertyValueItemValue isKindOfClass:[CMISPropertyData class]]) {
onlyPropertyData = NO;
break;
}
}
} else {
onlyPropertyData = NO;
}
break;
}
}
// Convert properties
if (onlyPropertyData) {
[self internalNormalConvertProperties:properties
typeDefinition:nil // not needed because all properties are of type CMISPropertyData
completionBlock:completionBlock];
} else {
//get secondary object type definitions - if available
NSString *propertyId = kCMISPropertySecondaryObjectTypeIds;
id secondaryObjectTypeIds = [properties valueForKey:propertyId];
if(secondaryObjectTypeIds) {
Class expectedType = nil;
BOOL validType = YES;
//verify types
expectedType = [NSArray class];
if([secondaryObjectTypeIds isKindOfClass:expectedType]){
expectedType = [NSString class];
for (id secondaryObjectTypeId in secondaryObjectTypeIds) {
propertyId = secondaryObjectTypeId;
if(![secondaryObjectTypeId isKindOfClass:expectedType]){
validType = NO;
break;
}
}
} else {
validType = NO;
}
if (!validType) {
NSError *error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeInvalidArgument
detailedDescription:[NSString stringWithFormat:@"Property value for %@ should be of type '%@'", propertyId, expectedType]];
completionBlock(nil, error);
return;
}
NSMutableArray *objectTypeIds = [NSMutableArray arrayWithObject:objectTypeId];
[objectTypeIds addObjectsFromArray:secondaryObjectTypeIds];
[self retrieveTypeDefinitions:objectTypeIds
completionBlock:^(NSArray *typeDefinitions, NSError *error) {
if (error) {
completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
} else {
[self internalNormalConvertProperties:properties
typeDefinitions:typeDefinitions
completionBlock:completionBlock];
}
}];
} else {
[self.session retrieveTypeDefinition:objectTypeId
completionBlock:^(CMISTypeDefinition *typeDefinition, NSError *error) {
if (error) {
completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
} else {
[self internalNormalConvertProperties:properties
typeDefinition:typeDefinition
completionBlock:completionBlock];
}
}];
}
}
}
- (void)retrieveTypeDefinitions:(NSArray *)objectTypeIds position:(NSInteger)position completionBlock:(void (^)(NSMutableArray *typeDefinitions, NSError *error))completionBlock
{
[self.session retrieveTypeDefinition:[objectTypeIds objectAtIndex:position]
completionBlock:^(CMISTypeDefinition *typeDefinition, NSError *error) {
if(error){
completionBlock(nil, error);
} else {
if (position == 0) {
NSMutableArray *typeDefinitions = [[NSMutableArray alloc] initWithCapacity:objectTypeIds.count];
[typeDefinitions addObject:typeDefinition];
completionBlock(typeDefinitions, error);
} else {
[self retrieveTypeDefinitions:objectTypeIds position:(position - 1) completionBlock:^(NSMutableArray *typeDefinitions, NSError *error) {
[typeDefinitions addObject:typeDefinition];
completionBlock(typeDefinitions, error);
}];
}
}
}];
}
- (void)retrieveTypeDefinitions:(NSArray *)objectTypeIds completionBlock:(void (^)(NSArray *typeDefinitions, NSError *error))completionBlock
{
if (objectTypeIds.count > 0) {
[self retrieveTypeDefinitions:objectTypeIds
position:(objectTypeIds.count - 1) // start recursion with last item
completionBlock:^(NSMutableArray *typeDefinitions, NSError *error) {
completionBlock(typeDefinitions, error);
}];
} else {
completionBlock([[NSArray alloc] init], nil);
}
}
+ (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