// ********************************************************************** // // Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #import #import #import #import #import #import #import #include #include #include #include #include namespace { std::map cachedObjects; NSString* operationModeToString(ICEOperationMode mode) { switch(mode) { case ICENormal: return @"::Ice::Normal"; case ICENonmutating: return @"::Ice::Nonmutating"; case ICEIdempotent: return @"::Ice::Idempotent"; default: return [NSString stringWithFormat:@"unknown value(%d)", mode]; } } class ObjectI : public IceObjC::ObjectWrapper, public Ice::BlobjectArrayAsync { public: ObjectI(ICEServant*); virtual void ice_invoke_async(const Ice::AMD_Object_ice_invokePtr&, const std::pair&, const Ice::Current&); virtual ICEObject* getObject() { return _object; } // We must explicitely CFRetain/CFRelease so that the garbage // collector does not trash the _object. virtual void __incRef() { CFRetain(_object); } virtual void __decRef() { CFRelease(_object); } private: ICEServant* _object; }; class BlobjectI : public IceObjC::ObjectWrapper, public Ice::BlobjectArrayAsync { public: BlobjectI(ICEBlobject*); virtual void ice_invoke_async(const Ice::AMD_Object_ice_invokePtr&, const std::pair&, const Ice::Current&); virtual ICEObject* getObject() { return _blobject; } // We must explicitely CFRetain/CFRelease so that the garbage // collector does not trash the _blobject. virtual void __incRef() { CFRetain(_blobject); } virtual void __decRef() { CFRelease(_blobject); } private: ICEBlobject* _blobject; id _target; }; ObjectI::ObjectI(ICEServant* object) : _object(object) { } void ObjectI::ice_invoke_async(const Ice::AMD_Object_ice_invokePtr& cb, const std::pair& inParams, const Ice::Current& current) { ICEInputStream* is = nil; ICEOutputStream* os = nil; { Ice::InputStreamPtr s = Ice::createInputStream(current.adapter->getCommunicator(), inParams); is = [ICEInputStream localObjectWithCxxObjectNoAutoRelease:s.get()]; } { Ice::OutputStreamPtr s = Ice::createOutputStream(current.adapter->getCommunicator()); os = [ICEOutputStream localObjectWithCxxObjectNoAutoRelease:s.get()]; } NSException* exception = nil; BOOL ok = YES; // Keep the compiler happy @autoreleasepool { ICECurrent* c = [[ICECurrent alloc] initWithCurrent:current]; @try { ok = [_object dispatch__:c is:is os:os]; } @catch(id ex) { exception = [ex retain]; } @finally { [c release]; [is release]; } } if(exception != nil) { [os release]; rethrowCxxException(exception, true); // True = release the exception. } std::vector outParams; [os os]->finished(outParams); [os release]; cb->ice_response(ok, std::make_pair(&outParams[0], &outParams[0] + outParams.size())); } BlobjectI::BlobjectI(ICEBlobject* blobject) : _blobject(blobject), _target([blobject target__]) { } void BlobjectI::ice_invoke_async(const Ice::AMD_Object_ice_invokePtr& cb, const std::pair& inEncaps, const Ice::Current& current) { NSException* exception = nil; BOOL ok = YES; // Keep the compiler happy. NSMutableData* outE = nil; @autoreleasepool { ICECurrent* c = [[ICECurrent alloc] initWithCurrent:current]; NSData* inE = [NSData dataWithBytesNoCopy:const_cast(inEncaps.first) length:(inEncaps.second - inEncaps.first) freeWhenDone:NO]; @try { ok = [_target ice_invoke:inE outEncaps:&outE current:c]; [outE retain]; } @catch(id ex) { exception = [ex retain]; } @finally { [c release]; } } if(exception != nil) { rethrowCxxException(exception, true); // True = release the exception. } cb->ice_response(ok, std::make_pair((ICEByte*)[outE bytes], (ICEByte*)[outE bytes] + [outE length])); [outE release]; } } int ICEInternalLookupString(NSString* const array[], size_t count, NSString* __unsafe_unretained str) { size_t low = 0; size_t high = count - 1; while(low <= high) { size_t mid = (low + high) / 2; switch([array[mid] compare:str]) { case NSOrderedDescending: if(mid == 0) { return -1; } high = mid - 1; break; case NSOrderedAscending: low = mid + 1; break; case NSOrderedSame: return mid; default: return -1; // Can't be reached } } return -1; } void ICEInternalCheckModeAndSelector(id target, ICEOperationMode expected, SEL sel, ICECurrent* current) { ICEOperationMode received = current.mode; if(expected != received) { if(expected == ICEIdempotent && received == ICENonmutating) { // // Fine: typically an old client still using the deprecated nonmutating keyword // // // Note that expected == Nonmutating and received == Idempotent is not ok: // the server may still use the deprecated nonmutating keyword to detect updates // and the client should not break this (deprecated) feature. // } else { ICEMarshalException* ex = [ICEMarshalException marshalException:__FILE__ line:__LINE__]; [ex setReason_:[NSString stringWithFormat:@"unexpected operation mode. expected = %@ received=%@", operationModeToString(expected), operationModeToString(received)]]; @throw ex; } } if(![target respondsToSelector:sel]) { @throw [ICEOperationNotExistException operationNotExistException:__FILE__ line:__LINE__ id:current.id_ facet:current.facet operation:current.operation]; } } @implementation ICEObject (ICEInternal) -(Ice::Object*) object__ { NSAssert(NO, @"object__ requires override"); return 0; } @end @implementation ICEObject static NSString* ICEObject_ids__[1] = { @"::Ice::Object" }; -(id)init { self = [super init]; if(!self) { return nil; } return self; } -(void) dealloc { [super dealloc]; } -(BOOL) ice_isA:(NSString*)typeId { return [self ice_isA:typeId current:nil]; } -(void) ice_ping { [self ice_ping:nil]; } -(NSString*) ice_id { return [self ice_id:nil]; } -(NSArray*) ice_ids { return [self ice_ids:nil]; } -(void) ice_preMarshal { } -(void) ice_postUnmarshal { } -(BOOL) ice_isA:(NSString*)typeId current:(ICECurrent*)current { NSAssert(NO, @"ice_isA requires override"); return nil; } -(void) ice_ping:(ICECurrent*)current { NSAssert(NO, @"ice_ping requires override"); } -(NSString*) ice_id:(ICECurrent*)current { NSAssert(NO, @"ice_id requires override"); return nil; } -(NSArray*) ice_ids:(ICECurrent*)current { NSAssert(NO, @"ice_ids requires override"); return nil; } -(BOOL) ice_dispatch:(id)request; { NSAssert(NO, @"ice_dispatch requires override"); return NO; } +(NSString*) ice_staticId { int count, index; NSString*const* staticIds = [self staticIds__:&count idIndex:&index]; return staticIds[index]; } +(NSString*const*) staticIds__:(int*)count idIndex:(int*)idx { *count = sizeof(ICEObject_ids__) / sizeof(NSString*); *idx = 0; return ICEObject_ids__; } -(void) write__:(id)os { NSAssert(NO, @"write__ requires override"); } -(void) read__:(id)is { NSAssert(NO, @"read__ requires override"); } -(id) copyWithZone:(NSZone*)zone { return [[[self class] allocWithZone:zone] init]; } @end @implementation ICEServant static NSString* ICEObject_all__[4] = { @"ice_id", @"ice_ids", @"ice_isA", @"ice_ping" }; -(id)init { self = [super init]; if(!self) { return nil; } object__ = 0; delegate__ = 0; return self; } -(id)initWithDelegate:(id)delegate { self = [super init]; if(!self) { return nil; } object__ = 0; delegate__ = [delegate retain]; return self; } -(void) dealloc { if(object__) { delete static_cast(object__); object__ = 0; } [delegate__ release]; [super dealloc]; } +(id)objectWithDelegate:(id)delegate { return [[[self alloc] initWithDelegate:delegate] autorelease]; } -(BOOL) ice_isA:(NSString*)typeId current:(ICECurrent*)current { int count, index; NSString*const* staticIds = [[self class] staticIds__:&count idIndex:&index]; return ICEInternalLookupString(staticIds, count, typeId) >= 0; } -(void) ice_ping:(ICECurrent*)current { // Nothing to do. } -(NSString*) ice_id:(ICECurrent*)current { return [[self class] ice_staticId]; } -(NSArray*) ice_ids:(ICECurrent*)current { int count, index; NSString*const* staticIds = [[self class] staticIds__:&count idIndex:&index]; return [NSArray arrayWithObjects:staticIds count:count]; } -(BOOL) ice_dispatch:(id)request { @try { ICERequest* requestI = (ICERequest*)request; return [requestI callDispatch:self]; } @catch(ICELocalException*) { @throw; } return FALSE; } +(BOOL) ice_isA___:(id)servant current:(ICECurrent*)current is:(id)is os:(id)os { ICEEncodingVersion* encoding = [is startEncapsulation]; NSString* id__ = [is readString]; [is endEncapsulation]; [os startEncapsulation:encoding format:ICEDefaultFormat]; BOOL ret__ = [servant ice_isA:id__ current:current]; [os writeBool:ret__]; [os endEncapsulation]; return YES; } +(BOOL) ice_ping___:(id)servant current:(ICECurrent*)current is:(id)is os:(id)os { ICEEncodingVersion* encoding = [is startEncapsulation]; [is endEncapsulation]; [os startEncapsulation:encoding format:ICEDefaultFormat]; [servant ice_ping:current]; [os endEncapsulation]; return YES; } +(BOOL) ice_id___:(id)servant current:(ICECurrent*)current is:(id)is os:(id)os { ICEEncodingVersion* encoding = [is startEncapsulation]; [is endEncapsulation]; [os startEncapsulation:encoding format:ICEDefaultFormat]; NSString* ret__ = [servant ice_id:current]; [os writeString:ret__]; [os endEncapsulation]; return YES; } +(BOOL) ice_ids___:(id)servant current:(ICECurrent*)current is:(id)is os:(id)os { ICEEncodingVersion* encoding = [is startEncapsulation]; [is endEncapsulation]; [os startEncapsulation:encoding format:ICEDefaultFormat]; NSArray* ret__ = [servant ice_ids:current]; [os writeStringSeq:ret__]; [os endEncapsulation]; return YES; } -(BOOL) dispatch__:(ICECurrent*)current is:(id)is os:(id)os { switch(ICEInternalLookupString(ICEObject_all__, sizeof(ICEObject_all__) / sizeof(NSString*), current.operation)) { case 0: return [ICEServant ice_id___:self current:current is:is os:os]; case 1: return [ICEServant ice_ids___:self current:current is:is os:os]; case 2: return [ICEServant ice_isA___:self current:current is:is os:os]; case 3: return [ICEServant ice_ping___:self current:current is:is os:os]; default: @throw [ICEOperationNotExistException requestFailedException:__FILE__ line:__LINE__ id:current.id_ facet:current.facet operation:current.operation]; } } -(void) write__:(id)os { [os startObject:nil]; [self writeImpl__:os]; [os endObject]; } -(void) read__:(id)is { [is startObject]; [self readImpl__:is]; [is endObject:NO]; } -(void) writeImpl__:(id)os { NSAssert(NO, @"writeImpl__ requires override"); } -(void) readImpl__:(id)is { NSAssert(NO, @"readImpl__ requires override"); } -(id)target__ { return (delegate__ == 0) ? self : delegate__; } -(Ice::Object*) object__ { @synchronized([self class]) { if(object__ == 0) { // // NOTE: IceObjC::ObjectI implements it own reference counting and there's no need // to call __incRef/__decRef here. The C++ object and Objective-C object are sharing // the same reference count (the one of the Objective-C object). This is necessary // to properly release both objects when there's either no more C++ handle/ObjC // reference to the object (without this, servants added to the object adapter // couldn't be retained or released easily). // object__ = static_cast(new ObjectI(self)); } } return static_cast(object__); } @end @implementation ICEBlobject -(Ice::Object*) object__ { @synchronized([self class]) { if(object__ == 0) { // // NOTE: IceObjC::ObjectI implements it own reference counting and there's no need // to call __incRef/__decRef here. The C++ object and Objective-C object are sharing // the same reference count (the one of the Objective-C object). This is necessary // to properly release both objects when there's either no more C++ handle/ObjC // reference to the object (without this, servants added to the object adapter // couldn't be retained or released easily). // object__ = static_cast(new BlobjectI(self)); } } return static_cast(object__); } @end @implementation ICEObjectWrapper -(id) initWithCxxObject:(Ice::Object*)arg { self = [super init]; if(!self) { return nil; } object__ = arg; object__->__incRef(); assert(cachedObjects.find(object__) == cachedObjects.end()); cachedObjects.insert(std::make_pair(object__, self)); return self; } -(void) dealloc { cachedObjects.erase(object__); object__->__decRef(); [super dealloc]; } +(id) objectWrapperWithCxxObject:(Ice::Object*)arg { @synchronized([ICEObjectWrapper class]) { std::map::const_iterator p = cachedObjects.find(arg); if(p != cachedObjects.end()) { return [p->second retain]; } else { return [[(ICEObjectWrapper*)[self alloc] initWithCxxObject:arg] autorelease]; } } } -(id) retain { NSIncrementExtraRefCount(self); return self; } -(oneway void) release { @synchronized([ICEObjectWrapper class]) { if(NSDecrementExtraRefCountWasZero(self)) { [self dealloc]; } } } -(BOOL) ice_isA:(NSString*)typeId current:(ICECurrent*)current { NSException* nsex = nil; try { return object__->ice_isA(fromNSString(typeId), Ice::Current()); } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; } -(void) ice_ping:(ICECurrent*)current { NSException* nsex = nil; try { return object__->ice_ping(Ice::Current()); } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; } -(NSString*) ice_id:(ICECurrent*)current { NSException* nsex = nil; try { return toNSString(object__->ice_id(Ice::Current())); } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; } -(NSArray*) ice_ids:(ICECurrent*)current { NSException* nsex = nil; try { return toNSArray(object__->ice_ids(Ice::Current())); } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; } -(BOOL) ice_dispatch:(id)request { @throw [ICEFeatureNotSupportedException featureNotSupportedException:__FILE__ line:__LINE__]; } -(void) write__:(id)os { NSException* nsex = nil; try { object__->__write([(ICEOutputStream*)os os]); } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; } -(void) read__:(id)is { NSException* nsex = nil; try { object__->__read([(ICEInputStream*)is is]); } catch(const std::exception& ex) { nsex = toObjCException(ex); } @throw nsex; } -(Ice::Object*) object__ { return object__; } @end