// // Copyright (c) ZeroC, Inc. All rights reserved. // #import #import #import #import #import #import #import #import #import #import #import #import #include #include #include #include #include #import #import #ifdef ICE_NO_KQUEUE # define ICE_USE_CFSTREAM 1 #endif extern "C" { Ice::Plugin* createIceSSL(const Ice::CommunicatorPtr&, const std::string&, const Ice::StringSeq&); Ice::Plugin* createIceDiscovery(const Ice::CommunicatorPtr&, const std::string&, const Ice::StringSeq&); Ice::Plugin* createIceLocatorDiscovery(const Ice::CommunicatorPtr&, const std::string&, const Ice::StringSeq&); #if defined(__APPLE__) && TARGET_OS_IPHONE > 0 Ice::Plugin* createIceIAP(const Ice::CommunicatorPtr&, const std::string&, const Ice::StringSeq&); #endif } namespace { typedef std::map CompactIdMap; IceUtil::Mutex* _compactIdMapMutex = 0; CompactIdMap* _compactIdMap = 0; class CompactIdResolverI : public Ice::CompactIdResolver { public: virtual ::std::string resolve(::Ice::Int value) const { assert(_compactIdMapMutex); assert(_compactIdMap); IceUtilInternal::MutexPtrLock lock(_compactIdMapMutex); CompactIdMap::iterator p = _compactIdMap->find(value); if(p != _compactIdMap->end()) { return p->second; } return ::std::string(); } }; // // We don't use the constructor to initialize the compactIdMap as // static initializtion takes place after +load is called. // class Init { public: ~Init() { if(_compactIdMap) { delete _compactIdMap; _compactIdMap = 0; } if(_compactIdMapMutex) { delete _compactIdMapMutex; _compactIdMapMutex = 0; } } }; Init init; } @implementation CompactIdMapHelper +(void) initialize { assert(!_compactIdMapMutex); assert(!_compactIdMap); _compactIdMapMutex = new ::IceUtil::Mutex; _compactIdMap = new CompactIdMap; } +(void) registerClass:(NSString*)type value:(ICEInt)value { assert(_compactIdMapMutex); assert(_compactIdMap); IceUtilInternal::MutexPtrLock lock(_compactIdMapMutex); CompactIdMap::iterator p = _compactIdMap->find(value); if(p != _compactIdMap->end()) { _compactIdMap->erase(p); } _compactIdMap->insert(CompactIdMap::value_type(value, fromNSString(type))); } @end namespace IceObjC { class ThreadNotification : public Ice::ThreadNotification, public IceUtil::Mutex { public: ThreadNotification() { } virtual void start() { Lock sync(*this); _pools.insert(std::make_pair(IceUtil::ThreadControl().id(), [[NSAutoreleasePool alloc] init])); } virtual void stop() { Lock sync(*this); std::map::iterator p = _pools.find(IceUtil::ThreadControl().id()); [p->second drain]; _pools.erase(p); } private: std::map _pools; }; }; @implementation ICEInitializationData (ICEInternal) -(Ice::InitializationData)initializationData { Ice::InitializationData data; data.properties = [(ICEProperties*)properties properties]; if(batchRequestInterceptor) { data.batchRequestInterceptor = [ICEBatchRequestInterceptor batchRequestInterceptorWithBatchRequestInterceptor:batchRequestInterceptor]; } if(dispatcher) { data.dispatcher = [ICEDispatcher dispatcherWithDispatcher:dispatcher]; } data.compactIdResolver = new CompactIdResolverI; return data; } @end @implementation ICEInitializationData @synthesize properties; @synthesize logger; @synthesize dispatcher; @synthesize batchRequestInterceptor; @synthesize prefixTable_; -(id) init:(id)props logger:(id)log dispatcher:(void(^)(id, id))d batchRequestInterceptor:(void(^)(id, int, int))i { self = [super init]; if(!self) { return nil; } properties = [props retain]; logger = [log retain]; dispatcher = [d copy]; batchRequestInterceptor = [i copy]; return self; } +(id) initializationData { ICEInitializationData *s = [[ICEInitializationData alloc] init]; [s autorelease]; return s; } +(id) initializationData:(id)p logger:(id)l dispatcher:(void(^)(id, id))d batchRequestInterceptor:(void(^)(id, int, int))i { return [[((ICEInitializationData *)[ICEInitializationData alloc]) init:p logger:l dispatcher:d batchRequestInterceptor:i] autorelease]; } -(id) copyWithZone:(NSZone *)zone { ICEInitializationData *copy = [ICEInitializationData allocWithZone:zone]; copy->properties = [properties retain]; copy->logger = [logger retain]; copy->dispatcher = [dispatcher copy]; copy->batchRequestInterceptor = [batchRequestInterceptor copy]; copy->prefixTable_ = [prefixTable_ retain]; return copy; } -(NSUInteger) hash { NSUInteger h = 0; h = (h << 5 ^ [properties hash]); h = (h << 5 ^ [logger hash]); h = (h << 5 ^ [dispatcher hash]); h = (h << 5 ^ [batchRequestInterceptor hash]); h = (h << 5 ^ [prefixTable_ hash]); return h; } -(BOOL) isEqual:(id)anObject { if(self == anObject) { return YES; } if(!anObject || ![anObject isKindOfClass:[self class]]) { return NO; } ICEInitializationData * obj =(ICEInitializationData *)anObject; if(!properties) { if(obj->properties) { return NO; } } else { if(![properties isEqual:obj->properties]) { return NO; } } if(!logger) { if(obj->logger) { return NO; } } else { if(![logger isEqual:obj->logger]) { return NO; } } if(!dispatcher) { if(obj->dispatcher) { return NO; } } else { if(dispatcher == obj->dispatcher) { return NO; } } if(!batchRequestInterceptor) { if(obj->batchRequestInterceptor) { return NO; } } else { if(batchRequestInterceptor == obj->batchRequestInterceptor) { return NO; } } if(!prefixTable_) { if(obj->prefixTable_) { return NO; } } else { if(![prefixTable_ isEqual:obj->prefixTable_]) { return NO; } } return YES; } -(void) dealloc { [properties release]; [logger release]; [dispatcher release]; [batchRequestInterceptor release]; [prefixTable_ release]; [super dealloc]; } @end @implementation ICEUtil +(id) createProperties { return [self createProperties:nil argv:nil]; } +(id) createProperties:(int*)argc argv:(char*[])argv { NSException* nsex = nil; try { Ice::PropertiesPtr properties; if(argc != nil && argv != nil) { properties = Ice::createProperties(*argc, argv); } else { properties = Ice::createProperties(); } return [ICEProperties localObjectWithCxxObject:properties.get()]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createCommunicator { return [self createCommunicator:nil argv:nil initData:nil]; } +(id) createCommunicator:(ICEInitializationData*)initData { return [self createCommunicator:nil argv:nil initData:initData]; } +(id) createCommunicator:(int*)argc argv:(char*[])argv { return [self createCommunicator:argc argv:argv initData:nil]; } +(id) createCommunicator:(int*)argc argv:(char*[])argv initData:(ICEInitializationData*)initData { if(![NSThread isMultiThreaded]) // Ensure sure Cocoa is multithreaded. { NSThread* thread = [[NSThread alloc] init]; [thread start]; [thread release]; } id properties = [initData properties]; if(properties != nil && ![properties isKindOfClass:[ICEProperties class]]) { @throw [ICEInitializationException initializationException:__FILE__ line:__LINE__ reason:@"properties were not created with createProperties"]; } NSException* nsex = nil; try { Ice::InitializationData data; if(initData != nil) { data = [initData initializationData]; } data.threadHook = new IceObjC::ThreadNotification(); if(!data.properties) { data.properties = Ice::createProperties(); } if(argc != nil && argv != nil) { data.properties = createProperties(*argc, argv, data.properties); } // // If no logger is specified, install a default logger unless Ice.UseSyslog // or Ice.LogFile is configured // if(!data.logger && data.properties->getPropertyAsInt("Ice.UseSyslog") <= 0 && data.properties->getProperty("Ice.LogFile").empty()) { id logger = initData ? initData.logger : nil; data.logger = [ICELogger loggerWithLogger:logger]; } Ice::CommunicatorPtr communicator; if(argc != nil && argv != nil) { communicator = Ice::initialize(*argc, argv, data); } else { communicator = Ice::initialize(data); } ICECommunicator* c = [ICECommunicator localObjectWithCxxObject:communicator.get()]; [c setup:initData]; return c; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createCommunicator:(int*)argc argv:(char*[])argv configFile:(NSString*)configFile { ICEInitializationData* initData = [ICEInitializationData initializationData]; initData.properties = [ICEUtil createProperties]; [initData.properties load:configFile]; return [self createCommunicator:argc argv:argv initData:initData]; } +(id) createInputStream:(id)c data:(NSData*)data { NSException* nsex = nil; try { return [[[ICEInputStream alloc] initWithCommunicator:c data:data encoding:nil] autorelease]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createInputStream:(id)c data:(NSData*)data encoding:(ICEEncodingVersion*)e { NSException* nsex = nil; try { return [[[ICEInputStream alloc] initWithCommunicator:c data:data encoding:e] autorelease]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createOutputStream:(id)communicator { NSException* nsex = nil; try { return [[[ICEOutputStream alloc] initWithCommunicator:communicator encoding:nil] autorelease]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(id) createOutputStream:(id)communicator encoding:(ICEEncodingVersion*)encoding { NSException* nsex = nil; try { return [[[ICEOutputStream alloc] initWithCommunicator:communicator encoding:encoding] autorelease]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(NSString*) generateUUID { return [NSString stringWithUTF8String:IceUtil::generateUUID().c_str()]; } +(NSArray*)argsToStringSeq:(int)argc argv:(char*[])argv { NSMutableArray* ns = [NSMutableArray array]; int i; for(i = 0; i < argc; ++i) { [ns addObject:[NSString stringWithCString:argv[i] encoding:NSUTF8StringEncoding]]; } return [[ns copy] autorelease]; } +(void)stringSeqToArgs:(NSArray*)args argc:(int*)argc argv:(char*[])argv { // // Shift all elements in argv which are present in args to the // beginning of argv. We record the original value of argc so // that we can know later if we've shifted the array. // const int argcOrig = *argc; int i = 0; while(i < *argc) { BOOL found = NO; for(NSString* s in args) { if([s compare:[NSString stringWithCString:argv[i] encoding:NSUTF8StringEncoding]] == 0) { found = YES; break; } } if(!found) { int j; for(j = i; j < *argc - 1; j++) { argv[j] = argv[j + 1]; } --(*argc); } else { ++i; } } // // Make sure that argv[*argc] == 0, the ISO C++ standard requires this. // We can only do this if we've shifted the array, otherwise argv[*argc] // may point to an invalid address. // if(argv && argcOrig != *argc) { argv[*argc] = 0; } } +(ICEIdentity*) stringToIdentity:(NSString*)str { NSException* nsex = nil; try { return [ICEIdentity identityWithIdentity:Ice::stringToIdentity(fromNSString(str))]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(NSMutableString*) identityToString:(ICEIdentity*)ident toStringMode:(ICEToStringMode)toStringMode { NSException* nsex = nil; try { return [toNSMutableString(Ice::identityToString([ident identity], static_cast(toStringMode))) autorelease]; } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; return nil; // Keep the compiler happy. } +(NSMutableString*) identityToString:(ICEIdentity*)ident { return [ICEUtil identityToString:ident toStringMode:ICEUnicode]; } @end @implementation ICEEncodingVersion(StringConv) +(ICEEncodingVersion*) encodingVersionWithString:(NSString*)str { return [ICEEncodingVersion encodingVersionWithEncodingVersion:Ice::stringToEncodingVersion(fromNSString(str))]; } @end @implementation ICEProtocolVersion(StringConv) +(ICEProtocolVersion*) protocolVersionWithString:(NSString*)str { return [ICEProtocolVersion protocolVersionWithProtocolVersion:Ice::stringToProtocolVersion(fromNSString(str))]; } @end