diff options
Diffstat (limited to 'php/src/php5/Communicator.cpp')
-rw-r--r-- | php/src/php5/Communicator.cpp | 771 |
1 files changed, 587 insertions, 184 deletions
diff --git a/php/src/php5/Communicator.cpp b/php/src/php5/Communicator.cpp index c1002bd046b..a541b426ebe 100644 --- a/php/src/php5/Communicator.cpp +++ b/php/src/php5/Communicator.cpp @@ -13,6 +13,7 @@ #include <Proxy.h> #include <Types.h> #include <Util.h> +#include <IceUtil/DisableWarnings.h> #include <IceUtil/Options.h> #include <IceUtil/MutexPtrLock.h> #include <IceUtil/StringUtil.h> @@ -30,6 +31,7 @@ namespace IcePHP { zend_class_entry* communicatorClassEntry = 0; +zend_class_entry* valueFactoryManagerClassEntry = 0; // // An active communicator is in use by at least one request and may have @@ -51,8 +53,19 @@ public: }; typedef IceUtil::Handle<ActiveCommunicator> ActiveCommunicatorPtr; -typedef std::map<std::string, zval*> ObjectFactoryMap; +class FactoryWrapper; +typedef IceUtil::Handle<FactoryWrapper> FactoryWrapperPtr; +class DefaultValueFactory; +typedef IceUtil::Handle<DefaultValueFactory> DefaultValueFactoryPtr; + +// +// CommunicatorInfoI encapsulates communicator-related information that +// is specific to a PHP "request". In other words, multiple PHP requests +// might share the same communicator instance but still need separate +// workspaces. For example, we don't want the value factories installed +// by one request to influence the behavior of another request. +// class CommunicatorInfoI : public CommunicatorInfo { public: @@ -65,44 +78,110 @@ public: virtual Ice::CommunicatorPtr getCommunicator() const; - bool addObjectFactory(const std::string&, zval* TSRMLS_DC); - bool findObjectFactory(const std::string&, zval* TSRMLS_DC); - void destroyObjectFactories(TSRMLS_D); + bool addFactory(zval*, const string&, bool TSRMLS_DC); + FactoryWrapperPtr findFactory(const string&) const; + Ice::ValueFactoryPtr defaultFactory() const { return _defaultFactory; } + void destroyFactories(TSRMLS_D); const ActiveCommunicatorPtr ac; const zval zv; - ObjectFactoryMap objectFactories; + +private: + + typedef map<string, FactoryWrapperPtr> FactoryMap; + + FactoryMap _factories; + DefaultValueFactoryPtr _defaultFactory; }; typedef IceUtil::Handle<CommunicatorInfoI> CommunicatorInfoIPtr; // -// Each PHP request has its own set of object factories. More precisely, there is -// an object factory map for each communicator that is created by a PHP request. -// The factory class defined below delegates the create/destroy methods to PHP -// objects supplied by the application. An instance of this class is installed -// as the communicator's default object factory, and the class holds a reference -// to its communicator. When create is invoked, the class resolves the appropriate -// PHP object as follows: +// Wraps a PHP object/value factory. +// +class FactoryWrapper : public Ice::ValueFactory +{ +public: + + FactoryWrapper(zval*, bool, const CommunicatorInfoIPtr&); + + virtual Ice::ValuePtr create(const string&); + + void getZval(zval* TSRMLS_DC); + + bool isObjectFactory() const; + + void destroy(TSRMLS_D); + +protected: + + zval* _factory; + bool _isObjectFactory; + CommunicatorInfoIPtr _info; +}; + +// +// Implements the default value factory behavior. +// +class DefaultValueFactory : public Ice::ValueFactory +{ +public: + + DefaultValueFactory(const CommunicatorInfoIPtr&); + + virtual Ice::ValuePtr create(const string&); + + void setDelegate(const FactoryWrapperPtr& d) { _delegate = d; } + FactoryWrapperPtr getDelegate() const { return _delegate; } + + void destroy(TSRMLS_D); + +private: + + FactoryWrapperPtr _delegate; + CommunicatorInfoIPtr _info; +}; + +// +// Each PHP request has its own set of value factories. More precisely, there is +// a value factory map for each communicator that is created by a PHP request. +// (see CommunicatorInfoI). +// +// We define a custom value factory manager implementation that delegates to +// to PHP objects supplied by the application. +// +// An instance of this class is installed as the communicator's value factory +// manager, and the class holds a reference to its communicator. When find() is +// invoked, the class resolves the appropriate factory as follows: // // * Using its communicator reference as the key, look up the corresponding // CommunicatorInfoI object in the request-specific communicator map. // -// * In the object factory map held by the CommunicatorInfoI object, look for a -// PHP factory object using the same algorithm as the Ice core. +// * If the type-id is empty, return the default factory. This factory will +// either delegate to an application-supplied default factory (if present) or +// default-construct an instance of a concrete Slice class type. +// +// * For non-empty type-ids, return a wrapper around the application-supplied +// factory, if any. // -class ObjectFactoryI : public Ice::ObjectFactory +class ValueFactoryManager : public Ice::ValueFactoryManager { public: - ObjectFactoryI(const Ice::CommunicatorPtr&); + virtual void add(const Ice::ValueFactoryPtr&, const string&); + virtual Ice::ValueFactoryPtr find(const string&) const; - virtual Ice::ObjectPtr create(const std::string&); - virtual void destroy(); + void setCommunicator(const Ice::CommunicatorPtr& c) { _communicator = c; } + Ice::CommunicatorPtr getCommunicator() const { return _communicator; } + + void getZval(zval* TSRMLS_DC); + + void destroy(); private: Ice::CommunicatorPtr _communicator; }; +typedef IceUtil::Handle<ValueFactoryManager> ValueFactoryManagerPtr; class ReaperTask : public IceUtil::TimerTask { @@ -121,6 +200,11 @@ namespace zend_object_handlers _handlers; // +// ValueFactoryManager support. +// +zend_object_handlers _vfmHandlers; + +// // The profile map holds Properties objects corresponding to the "default" profile // (defined via the ice.config & ice.options settings in php.ini) as well as named // profiles defined in an external file. @@ -154,7 +238,7 @@ public: { _registeredCommunicatorsMutex = new IceUtil::Mutex(); } - + ~Init() { delete _registeredCommunicatorsMutex; @@ -170,6 +254,10 @@ extern "C" static zend_object_value handleAlloc(zend_class_entry* TSRMLS_DC); static void handleFreeStorage(void* TSRMLS_DC); static zend_object_value handleClone(zval* TSRMLS_DC); + +static zend_object_value handleVfmAlloc(zend_class_entry* TSRMLS_DC); +static void handleVfmFreeStorage(void* TSRMLS_DC); +static zend_object_value handleVfmClone(zval* TSRMLS_DC); } ZEND_METHOD(Ice_Communicator, __construct) @@ -195,9 +283,9 @@ ZEND_METHOD(Ice_Communicator, destroy) } // - // We need to destroy any object factories installed by this request. + // We need to destroy any object|value factories installed by this request. // - _this->destroyObjectFactories(TSRMLS_C); + _this->destroyFactories(TSRMLS_C); Ice::CommunicatorPtr c = _this->getCommunicator(); assert(c); @@ -206,6 +294,10 @@ ZEND_METHOD(Ice_Communicator, destroy) assert(m->find(c) != m->end()); m->erase(c); + ValueFactoryManagerPtr vfm = ValueFactoryManagerPtr::dynamicCast(c->getValueFactoryManager()); + assert(vfm); + vfm->destroy(); + try { c->destroy(); @@ -262,7 +354,7 @@ ZEND_METHOD(Ice_Communicator, proxyToString) if(zv) { Ice::ObjectPrx prx; - ClassInfoPtr info; + ProxyInfoPtr info; if(!fetchProxy(zv, prx, info TSRMLS_CC)) { RETURN_NULL(); @@ -328,13 +420,13 @@ ZEND_METHOD(Ice_Communicator, proxyToProperty) if(zv) { Ice::ObjectPrx prx; - ClassInfoPtr info; + ProxyInfoPtr info; if(!fetchProxy(zv, prx, info TSRMLS_CC)) { RETURN_NULL(); } assert(prx); - + Ice::PropertyDict val = _this->getCommunicator()->proxyToProperty(prx, prefix); if(!createStringMap(return_value, val TSRMLS_CC)) { @@ -435,7 +527,7 @@ ZEND_METHOD(Ice_Communicator, addObjectFactory) type = string(id, idLen); } - if(!_this->addObjectFactory(type, factory TSRMLS_CC)) + if(!_this->addFactory(factory, type, true TSRMLS_CC)) { RETURN_NULL(); } @@ -459,8 +551,45 @@ ZEND_METHOD(Ice_Communicator, findObjectFactory) type = string(id, idLen); } - if(!_this->findObjectFactory(type, return_value TSRMLS_CC)) + FactoryWrapperPtr w = _this->findFactory(type); + if(w && w->isObjectFactory()) + { + w->getZval(return_value TSRMLS_CC); + } + else + { + RETURN_NULL(); + } +} + +ZEND_METHOD(Ice_Communicator, getValueFactoryManager) +{ + if(ZEND_NUM_ARGS() > 0) + { + WRONG_PARAM_COUNT; + } + + CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC); + assert(_this); + + try + { + ValueFactoryManagerPtr vfm = + ValueFactoryManagerPtr::dynamicCast(_this->getCommunicator()->getValueFactoryManager()); + assert(vfm); + if(object_init_ex(return_value, valueFactoryManagerClassEntry) != SUCCESS) + { + runtimeError("unable to initialize properties object" TSRMLS_CC); + RETURN_NULL(); + } + + Wrapper<ValueFactoryManagerPtr>* obj = Wrapper<ValueFactoryManagerPtr>::extract(return_value TSRMLS_CC); + assert(!obj->ptr); + obj->ptr = new ValueFactoryManagerPtr(vfm); + } + catch(const IceUtil::Exception& ex) { + throwException(ex TSRMLS_CC); RETURN_NULL(); } } @@ -501,7 +630,7 @@ ZEND_METHOD(Ice_Communicator, getLogger) { WRONG_PARAM_COUNT; } - + CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC); assert(_this); @@ -535,7 +664,7 @@ ZEND_METHOD(Ice_Communicator, getDefaultRouter) Ice::RouterPrx router = _this->getCommunicator()->getDefaultRouter(); if(router) { - ClassInfoPtr info = getClassInfoById("::Ice::Router" TSRMLS_CC); + ProxyInfoPtr info = getProxyInfo("::Ice::Router" TSRMLS_CC); if(!info) { runtimeError("no definition for Ice::Router" TSRMLS_CC); @@ -571,7 +700,7 @@ ZEND_METHOD(Ice_Communicator, setDefaultRouter) } Ice::ObjectPrx proxy; - ClassInfoPtr info; + ProxyInfoPtr info; if(zv && !fetchProxy(zv, proxy, info TSRMLS_CC)) { RETURN_NULL(); @@ -613,7 +742,7 @@ ZEND_METHOD(Ice_Communicator, getDefaultLocator) Ice::LocatorPrx locator = _this->getCommunicator()->getDefaultLocator(); if(locator) { - ClassInfoPtr info = getClassInfoById("::Ice::Locator" TSRMLS_CC); + ProxyInfoPtr info = getProxyInfo("::Ice::Locator" TSRMLS_CC); if(!info) { runtimeError("no definition for Ice::Locator" TSRMLS_CC); @@ -649,7 +778,7 @@ ZEND_METHOD(Ice_Communicator, setDefaultLocator) } Ice::ObjectPrx proxy; - ClassInfoPtr info; + ProxyInfoPtr info; if(zv && !fetchProxy(zv, proxy, info TSRMLS_CC)) { RETURN_NULL(); @@ -678,17 +807,25 @@ ZEND_METHOD(Ice_Communicator, setDefaultLocator) ZEND_METHOD(Ice_Communicator, flushBatchRequests) { - CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC); - assert(_this); + zval* compress; + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("z"), &compress TSRMLS_CC) != SUCCESS) + { + RETURN_NULL(); + } - if(ZEND_NUM_ARGS() != 8) + if(Z_TYPE_P(compress) != IS_LONG) { - WRONG_PARAM_COUNT; + invalidArgument("value for 'compress' argument must be an enumerator of CompressBatch" TSRMLS_CC); + RETURN_NULL(); } + Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(Z_LVAL_P(compress)); + + CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC); + assert(_this); try { - _this->getCommunicator()->flushBatchRequests(); + _this->getCommunicator()->flushBatchRequests(cb); } catch(const IceUtil::Exception& ex) { @@ -697,6 +834,83 @@ ZEND_METHOD(Ice_Communicator, flushBatchRequests) } } +ZEND_METHOD(Ice_ValueFactoryManager, __construct) +{ + runtimeError("value factory managers cannot be instantiated directly" TSRMLS_CC); +} + +ZEND_METHOD(Ice_ValueFactoryManager, add) +{ + ValueFactoryManagerPtr _this = Wrapper<ValueFactoryManagerPtr>::value(getThis() TSRMLS_CC); + assert(_this); + + zend_class_entry* factoryClass = idToClass("Ice::ValueFactory" TSRMLS_CC); + assert(factoryClass); + + zval* factory; + char* id; + int idLen; + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("Os!"), &factory, factoryClass, &id, + &idLen TSRMLS_CC) != SUCCESS) + { + RETURN_NULL(); + } + + string type; + if(id) + { + type = string(id, idLen); + } + + CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap)); + assert(m); + CommunicatorMap::iterator p = m->find(_this->getCommunicator()); + assert(p != m->end()); + + CommunicatorInfoIPtr info = p->second; + + if(!info->addFactory(factory, type, false TSRMLS_CC)) + { + RETURN_NULL(); + } +} + +ZEND_METHOD(Ice_ValueFactoryManager, find) +{ + ValueFactoryManagerPtr _this = Wrapper<ValueFactoryManagerPtr>::value(getThis() TSRMLS_CC); + assert(_this); + + char* id; + int idLen; + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s!"), &id, &idLen TSRMLS_CC) != SUCCESS) + { + RETURN_NULL(); + } + + string type; + if(id) + { + type = string(id, idLen); + } + + CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap)); + assert(m); + CommunicatorMap::iterator p = m->find(_this->getCommunicator()); + assert(p != m->end()); + + CommunicatorInfoIPtr info = p->second; + + FactoryWrapperPtr w = info->findFactory(type); + if(w) + { + w->getZval(return_value TSRMLS_CC); + } + else + { + RETURN_NULL(); + } +} + #ifdef _WIN32 extern "C" #endif @@ -736,6 +950,46 @@ handleClone(zval* zv TSRMLS_DC) return zend_object_value(); } +#ifdef _WIN32 +extern "C" +#endif +static zend_object_value +handleVfmAlloc(zend_class_entry* ce TSRMLS_DC) +{ + zend_object_value result; + + Wrapper<ValueFactoryManagerPtr>* obj = Wrapper<ValueFactoryManagerPtr>::create(ce TSRMLS_CC); + assert(obj); + + result.handle = + zend_objects_store_put(obj, 0, (zend_objects_free_object_storage_t)handleVfmFreeStorage, 0 TSRMLS_CC); + result.handlers = &_vfmHandlers; + + return result; +} + +#ifdef _WIN32 +extern "C" +#endif +static void +handleVfmFreeStorage(void* p TSRMLS_DC) +{ + Wrapper<ValueFactoryManagerPtr>* obj = static_cast<Wrapper<ValueFactoryManagerPtr>*>(p); + delete obj->ptr; + zend_object_std_dtor(static_cast<zend_object*>(p) TSRMLS_CC); + efree(p); +} + +#ifdef _WIN32 +extern "C" +#endif +static zend_object_value +handleVfmClone(zval* zv TSRMLS_DC) +{ + php_error_docref(0 TSRMLS_CC, E_ERROR, "value factory managers cannot be cloned"); + return zend_object_value(); +} + static CommunicatorInfoIPtr createCommunicator(zval* zv, const ActiveCommunicatorPtr& ac TSRMLS_DC) { @@ -791,10 +1045,9 @@ initializeCommunicator(zval* zv, Ice::StringSeq& args, bool hasArgs, const Ice:: ActiveCommunicatorPtr ac = new ActiveCommunicator(c); - // - // Install a default object factory that delegates to PHP factories. - // - c->addObjectFactory(new ObjectFactoryI(c), ""); + ValueFactoryManagerPtr vfm = ValueFactoryManagerPtr::dynamicCast(c->getValueFactoryManager()); + assert(vfm); + vfm->setCommunicator(c); CommunicatorInfoIPtr info = createCommunicator(zv, ac TSRMLS_CC); if(!info) @@ -806,6 +1059,8 @@ initializeCommunicator(zval* zv, Ice::StringSeq& args, bool hasArgs, const Ice:: catch(...) { } + + vfm->destroy(); } return info; @@ -897,7 +1152,8 @@ ZEND_FUNCTION(Ice_initialize) string member; member = "properties"; - if(zend_hash_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), static_cast<uint>(member.size() + 1), &data) == SUCCESS) + if(zend_hash_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), static_cast<uint>(member.size() + 1), &data) + == SUCCESS) { zval** val = reinterpret_cast<zval**>(data); if(!fetchProperties(*val, initData.properties TSRMLS_CC)) @@ -907,7 +1163,8 @@ ZEND_FUNCTION(Ice_initialize) } member = "logger"; - if(zend_hash_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), static_cast<uint>(member.size() + 1), &data) == SUCCESS) + if(zend_hash_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), static_cast<uint>(member.size() + 1), &data) + == SUCCESS) { zval** val = reinterpret_cast<zval**>(data); if(!fetchLogger(*val, initData.logger TSRMLS_CC)) @@ -918,6 +1175,7 @@ ZEND_FUNCTION(Ice_initialize) } initData.compactIdResolver = new IdResolver(TSRMLS_C); + initData.valueFactoryManager = new ValueFactoryManager; CommunicatorInfoIPtr info = initializeCommunicator(return_value, seq, hasArgs, initData TSRMLS_CC); if(!info) @@ -1115,7 +1373,9 @@ ZEND_FUNCTION(Ice_identityToString) assert(identityClass); zval* zv; - if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, identityClass) != SUCCESS) + long mode = 0; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O|l"), &zv, identityClass, &mode TSRMLS_CC) != SUCCESS) { RETURN_NULL(); } @@ -1127,7 +1387,7 @@ ZEND_FUNCTION(Ice_identityToString) try { - string str = Ice::identityToString(id); + string str = identityToString(id, static_cast<Ice::ToStringMode>(mode)); RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()), 1); } catch(const IceUtil::Exception& ex) @@ -1179,24 +1439,40 @@ static zend_function_entry _interfaceMethods[] = }; static zend_function_entry _classMethods[] = { - ZEND_ME(Ice_Communicator, __construct, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR) - ZEND_ME(Ice_Communicator, destroy, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, stringToProxy, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, proxyToString, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, propertyToProxy, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, proxyToProperty, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, stringToIdentity, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, identityToString, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, addObjectFactory, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, findObjectFactory, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, getImplicitContext, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, getProperties, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, getLogger, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, getDefaultRouter, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, setDefaultRouter, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, getDefaultLocator, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, setDefaultLocator, NULL, ZEND_ACC_PUBLIC) - ZEND_ME(Ice_Communicator, flushBatchRequests, NULL, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, __construct, ICE_NULLPTR, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR) + ZEND_ME(Ice_Communicator, destroy, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, stringToProxy, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, proxyToString, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, propertyToProxy, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, proxyToProperty, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, stringToIdentity, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, identityToString, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, addObjectFactory, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, findObjectFactory, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, getValueFactoryManager, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, getImplicitContext, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, getProperties, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, getLogger, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, getDefaultRouter, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, setDefaultRouter, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, getDefaultLocator, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, setDefaultLocator, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Communicator, flushBatchRequests, ICE_NULLPTR, ZEND_ACC_PUBLIC) + {0, 0, 0} +}; + +// +// Predefined methods for ValueFactoryManager. +// +static zend_function_entry _vfmInterfaceMethods[] = +{ + {0, 0, 0} +}; +static zend_function_entry _vfmClassMethods[] = +{ + ZEND_ME(Ice_ValueFactoryManager, __construct, ICE_NULLPTR, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR) + ZEND_ME(Ice_ValueFactoryManager, add, ICE_NULLPTR, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_ValueFactoryManager, find, ICE_NULLPTR, ZEND_ACC_PUBLIC) {0, 0, 0} }; @@ -1410,6 +1686,26 @@ IcePHP::communicatorInit(TSRMLS_D) zend_class_implements(communicatorClassEntry TSRMLS_CC, 1, interface); // + // Register the ValueFactoryManager interface. + // +#ifdef ICEPHP_USE_NAMESPACES + INIT_NS_CLASS_ENTRY(ce, "Ice", "ValueFactoryManager", _vfmInterfaceMethods); +#else + INIT_CLASS_ENTRY(ce, "Ice_ValueFactoryManager", _vfmInterfaceMethods); +#endif + zend_class_entry* vfmInterface = zend_register_internal_interface(&ce TSRMLS_CC); + + // + // Register the ValueFactoryManager class. + // + INIT_CLASS_ENTRY(ce, "IcePHP_ValueFactoryManager", _vfmClassMethods); + ce.create_object = handleVfmAlloc; + valueFactoryManagerClassEntry = zend_register_internal_class(&ce TSRMLS_CC); + memcpy(&_vfmHandlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + _vfmHandlers.clone_obj = handleVfmClone; + zend_class_implements(valueFactoryManagerClassEntry TSRMLS_CC, 1, vfmInterface); + + // // Create the profiles from configuration settings. // const char* empty = ""; @@ -1501,9 +1797,9 @@ IcePHP::communicatorRequestShutdown(TSRMLS_D) CommunicatorInfoIPtr info = p->second; // - // We need to destroy any object factories installed during this request. + // We need to destroy any object|value factories installed during this request. // - info->destroyObjectFactories(TSRMLS_C); + info->destroyFactories(TSRMLS_C); } // @@ -1536,121 +1832,131 @@ IcePHP::ActiveCommunicator::~ActiveCommunicator() } } -IcePHP::CommunicatorInfoI::CommunicatorInfoI(const ActiveCommunicatorPtr& c, zval* z) : - ac(c), - zv(*z) // This is legal - it simply copies the object's handle. +IcePHP::FactoryWrapper::FactoryWrapper(zval* factory, bool isObjectFactory, const CommunicatorInfoIPtr& info) : + _factory(factory), + _isObjectFactory(isObjectFactory), + _info(info) { + Z_ADDREF_P(_factory); } -void -IcePHP::CommunicatorInfoI::getZval(zval* z TSRMLS_DC) +Ice::ValuePtr +IcePHP::FactoryWrapper::create(const string& id) { - Z_TYPE_P(z) = IS_OBJECT; - z->value.obj = zv.value.obj; - addRef(TSRMLS_C); -} + // + // Get the TSRM id for the current request. + // + TSRMLS_FETCH(); -void -IcePHP::CommunicatorInfoI::addRef(TSRMLS_D) -{ - zval* p = const_cast<zval*>(&zv); - Z_OBJ_HT_P(p)->add_ref(p TSRMLS_CC); -} + // + // Get the type information. + // + ClassInfoPtr cls; + if(id == Ice::Object::ice_staticId()) + { + // + // When the ID is that of Ice::Object, it indicates that the stream has not + // found a factory and is providing us an opportunity to preserve the object. + // + cls = getClassInfoById("::Ice::UnknownSlicedValue" TSRMLS_CC); + } + else + { + cls = getClassInfoById(id TSRMLS_CC); + } -void -IcePHP::CommunicatorInfoI::decRef(TSRMLS_D) -{ - zval* p = const_cast<zval*>(&zv); - Z_OBJ_HT(zv)->del_ref(p TSRMLS_CC); -} + if(!cls) + { + return 0; + } -Ice::CommunicatorPtr -IcePHP::CommunicatorInfoI::getCommunicator() const -{ - return ac->communicator; -} + zval* arg; + MAKE_STD_ZVAL(arg); + ZVAL_STRINGL(arg, STRCAST(id.c_str()), static_cast<int>(id.length()), 1); -bool -IcePHP::CommunicatorInfoI::addObjectFactory(const string& id, zval* factory TSRMLS_DC) -{ - ObjectFactoryMap::iterator p = objectFactories.find(id); - if(p != objectFactories.end()) + zval* obj = 0; + + zend_try { - Ice::AlreadyRegisteredException ex(__FILE__, __LINE__); - ex.kindOfObject = "object factory"; - ex.id = id; - throwException(ex TSRMLS_CC); - return false; + const char* func = "create"; + zend_call_method(&_factory, 0, 0, const_cast<char*>(func), static_cast<int>(strlen(func)), &obj, 1, arg, + 0 TSRMLS_CC); } + zend_catch + { + obj = 0; + } + zend_end_try(); - objectFactories.insert(ObjectFactoryMap::value_type(id, factory)); - Z_ADDREF_P(factory); + zval_ptr_dtor(&arg); - return true; -} + // + // Bail out if an exception has already been thrown. + // + if(!obj || EG(exception)) + { + throw AbortMarshaling(); + } -bool -IcePHP::CommunicatorInfoI::findObjectFactory(const string& id, zval* zv TSRMLS_DC) -{ - ObjectFactoryMap::iterator p = objectFactories.find(id); - if(p != objectFactories.end()) + AutoDestroy destroy(obj); + + if(Z_TYPE_P(obj) == IS_NULL) { - *zv = *p->second; // This is legal - it simply copies the object's handle. - INIT_PZVAL(zv); - zval_copy_ctor(zv); - return true; + return 0; } - return false; + return new ObjectReader(obj, cls, _info TSRMLS_CC); +} + +void +IcePHP::FactoryWrapper::getZval(zval* factory TSRMLS_DC) +{ + *factory = *_factory; // This is legal - it simply copies the object's handle. + INIT_PZVAL(factory); + zval_copy_ctor(factory); +} + +bool +IcePHP::FactoryWrapper::isObjectFactory() const +{ + return _isObjectFactory; } void -IcePHP::CommunicatorInfoI::destroyObjectFactories(TSRMLS_D) +IcePHP::FactoryWrapper::destroy(TSRMLS_D) { - for(ObjectFactoryMap::iterator p = objectFactories.begin(); p != objectFactories.end(); ++p) + if(_isObjectFactory) { // - // Invoke the destroy method on each registered PHP factory. + // Invoke the destroy method on the PHP factory. // - invokeMethod(p->second, "destroy" TSRMLS_CC); + invokeMethod(_factory, "destroy" TSRMLS_CC); zend_clear_exception(TSRMLS_C); - zval_ptr_dtor(&p->second); } + zval_ptr_dtor(&_factory); + _info = 0; } -IcePHP::ObjectFactoryI::ObjectFactoryI(const Ice::CommunicatorPtr& communicator) : - _communicator(communicator) +IcePHP::DefaultValueFactory::DefaultValueFactory(const CommunicatorInfoIPtr& info) : + _info(info) { } -Ice::ObjectPtr -IcePHP::ObjectFactoryI::create(const string& id) +Ice::ValuePtr +IcePHP::DefaultValueFactory::create(const string& id) { // // Get the TSRM id for the current request. // TSRMLS_FETCH(); - CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap)); - assert(m); - CommunicatorMap::iterator p = m->find(_communicator); - assert(p != m->end()); - - CommunicatorInfoIPtr info = p->second; - - zval* factory = 0; - - // - // Check if the application has registered a factory for this id. - // - ObjectFactoryMap::iterator q = info->objectFactories.find(id); - if(q == info->objectFactories.end()) + if(_delegate) { - q = info->objectFactories.find(""); // Look for a default factory. - } - if(q != info->objectFactories.end()) - { - factory = q->second; + Ice::ValuePtr v = _delegate->create(id); + if(v) + { + return v; + } } // @@ -1663,7 +1969,7 @@ IcePHP::ObjectFactoryI::create(const string& id) // When the ID is that of Ice::Object, it indicates that the stream has not // found a factory and is providing us an opportunity to preserve the object. // - cls = getClassInfoById("::Ice::UnknownSlicedObject" TSRMLS_CC); + cls = getClassInfoById("::Ice::UnknownSlicedValue" TSRMLS_CC); } else { @@ -1675,75 +1981,172 @@ IcePHP::ObjectFactoryI::create(const string& id) return 0; } - if(factory) + // + // Instantiate the object. + // + zval* obj; + MAKE_STD_ZVAL(obj); + AutoDestroy destroy(obj); + + if(object_init_ex(obj, const_cast<zend_class_entry*>(cls->zce)) != SUCCESS) + { + throw AbortMarshaling(); + } + + if(!invokeMethod(obj, ZEND_CONSTRUCTOR_FUNC_NAME TSRMLS_CC)) + { + throw AbortMarshaling(); + } + + return new ObjectReader(obj, cls, _info TSRMLS_CC); +} + +void +IcePHP::DefaultValueFactory::destroy(TSRMLS_D) +{ + if(_delegate) { - zval* arg; - MAKE_STD_ZVAL(arg); - ZVAL_STRINGL(arg, STRCAST(id.c_str()), static_cast<int>(id.length()), 1); + _delegate->destroy(); + _delegate = 0; + } + _info = 0; +} + +IcePHP::CommunicatorInfoI::CommunicatorInfoI(const ActiveCommunicatorPtr& c, zval* z) : + ac(c), + zv(*z), // This is legal - it simply copies the object's handle. + _defaultFactory(new DefaultValueFactory(this)) +{ +} - zval* obj = 0; +void +IcePHP::CommunicatorInfoI::getZval(zval* z TSRMLS_DC) +{ + Z_TYPE_P(z) = IS_OBJECT; + z->value.obj = zv.value.obj; + addRef(TSRMLS_C); +} - zend_try - { - const char* func = "create"; - zend_call_method(&factory, 0, 0, const_cast<char*>(func), static_cast<int>(strlen(func)), &obj, 1, arg, 0 TSRMLS_CC); - } - zend_catch +void +IcePHP::CommunicatorInfoI::addRef(TSRMLS_D) +{ + zval* p = const_cast<zval*>(&zv); + Z_OBJ_HT_P(p)->add_ref(p TSRMLS_CC); +} + +void +IcePHP::CommunicatorInfoI::decRef(TSRMLS_D) +{ + zval* p = const_cast<zval*>(&zv); + Z_OBJ_HT(zv)->del_ref(p TSRMLS_CC); +} + +Ice::CommunicatorPtr +IcePHP::CommunicatorInfoI::getCommunicator() const +{ + return ac->communicator; +} + +bool +IcePHP::CommunicatorInfoI::addFactory(zval* factory, const string& id, bool isObjectFactory TSRMLS_DC) +{ + if(id.empty()) + { + if(_defaultFactory->getDelegate()) { - obj = 0; + Ice::AlreadyRegisteredException ex(__FILE__, __LINE__); + ex.kindOfObject = "value factory"; + ex.id = id; + throwException(ex TSRMLS_CC); + return false; } - zend_end_try(); - zval_ptr_dtor(&arg); - - // - // Bail out if an exception has already been thrown. - // - if(!obj || EG(exception)) + _defaultFactory->setDelegate(new FactoryWrapper(factory, isObjectFactory, this)); + } + else + { + FactoryMap::iterator p = _factories.find(id); + if(p != _factories.end()) { - throw AbortMarshaling(); + Ice::AlreadyRegisteredException ex(__FILE__, __LINE__); + ex.kindOfObject = "value factory"; + ex.id = id; + throwException(ex TSRMLS_CC); + return false; } - AutoDestroy destroy(obj); + _factories.insert(FactoryMap::value_type(id, new FactoryWrapper(factory, isObjectFactory, this))); + } - if(Z_TYPE_P(obj) == IS_NULL) + return true; +} + +FactoryWrapperPtr +IcePHP::CommunicatorInfoI::findFactory(const string& id) const +{ + if(id.empty()) + { + return _defaultFactory->getDelegate(); + } + else + { + FactoryMap::const_iterator p = _factories.find(id); + if(p != _factories.end()) { - return 0; + return p->second; } + } - return new ObjectReader(obj, cls, info TSRMLS_CC); + return 0; +} + +void +IcePHP::CommunicatorInfoI::destroyFactories(TSRMLS_D) +{ + for(FactoryMap::iterator p = _factories.begin(); p != _factories.end(); ++p) + { + p->second->destroy(TSRMLS_C); } + _factories.clear(); + _defaultFactory->destroy(TSRMLS_C); +} +void +IcePHP::ValueFactoryManager::add(const Ice::ValueFactoryPtr&, const string&) +{ // - // If the requested type is an abstract class, then we give up. + // We don't support factories registered in C++. // - if(cls->isAbstract) - { - return 0; - } + throw Ice::FeatureNotSupportedException(__FILE__, __LINE__, "C++ value factory"); +} +Ice::ValueFactoryPtr +IcePHP::ValueFactoryManager::find(const string& id) const +{ // - // Instantiate the object. + // Get the TSRM id for the current request. // - zval* obj; - MAKE_STD_ZVAL(obj); - AutoDestroy destroy(obj); + TSRMLS_FETCH(); - if(object_init_ex(obj, const_cast<zend_class_entry*>(cls->zce)) != SUCCESS) + CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap)); + assert(m); + CommunicatorMap::iterator p = m->find(_communicator); + assert(p != m->end()); + + CommunicatorInfoIPtr info = p->second; + + if(id.empty()) { - throw AbortMarshaling(); + return info->defaultFactory(); } - - if(!invokeMethod(obj, ZEND_CONSTRUCTOR_FUNC_NAME TSRMLS_CC)) + else { - throw AbortMarshaling(); + return info->findFactory(id); } - - return new ObjectReader(obj, cls, info TSRMLS_CC); } void -IcePHP::ObjectFactoryI::destroy() +IcePHP::ValueFactoryManager::destroy() { _communicator = 0; } |