summaryrefslogtreecommitdiff
path: root/php/src/IcePHP/Communicator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'php/src/IcePHP/Communicator.cpp')
-rw-r--r--php/src/IcePHP/Communicator.cpp1651
1 files changed, 1252 insertions, 399 deletions
diff --git a/php/src/IcePHP/Communicator.cpp b/php/src/IcePHP/Communicator.cpp
index 40a315a3f84..ca48dc52565 100644
--- a/php/src/IcePHP/Communicator.cpp
+++ b/php/src/IcePHP/Communicator.cpp
@@ -7,11 +7,14 @@
//
// **********************************************************************
-#include <IceUtil/DisableWarnings.h>
#include <Communicator.h>
+#include <Logger.h>
+#include <Properties.h>
#include <Proxy.h>
-#include <Marshal.h>
#include <Util.h>
+#include <IceUtil/Options.h>
+#include <IceUtil/StaticMutex.h>
+#include <IceUtil/Timer.h>
using namespace std;
using namespace IcePHP;
@@ -21,704 +24,1554 @@ ZEND_EXTERN_MODULE_GLOBALS(ice)
//
// Class entries represent the PHP class implementations we have registered.
//
-static zend_class_entry* _communicatorClassEntry;
+namespace IcePHP
+{
+
+zend_class_entry* communicatorClassEntry = 0;
//
-// Ice::Communicator support.
+// An active communicator is in use by at least one request and may have
+// registered so that it remains active after a request completes. The
+// communicator is destroyed when there are no more references to this
+// object.
//
-static zend_object_handlers _handlers;
+class ActiveCommunicator : public IceUtil::Shared
+{
+public:
-extern "C"
+ ActiveCommunicator(const Ice::CommunicatorPtr& c);
+ ~ActiveCommunicator();
+
+ const Ice::CommunicatorPtr communicator;
+ vector<string> ids;
+ int expires;
+ IceUtil::Time lastAccess;
+};
+typedef IceUtil::Handle<ActiveCommunicator> ActiveCommunicatorPtr;
+
+typedef std::map<std::string, zval*> ObjectFactoryMap;
+
+class CommunicatorInfoI : public CommunicatorInfo
{
-static zend_object_value handleAlloc(zend_class_entry* TSRMLS_DC);
-static zend_object_value handleClone(zval* TSRMLS_DC);
-static void handleFreeStorage(void* TSRMLS_DC);
+public:
-static union _zend_function* handleGetMethod(zval**, char*, int TSRMLS_DC);
-}
+ CommunicatorInfoI(const ActiveCommunicatorPtr&, zval*);
+
+ virtual void getZval(zval* TSRMLS_DC);
+ virtual void addRef(TSRMLS_D);
+ virtual void decRef(TSRMLS_D);
+
+ virtual Ice::CommunicatorPtr getCommunicator() const;
-static void initCommunicator(ice_object* TSRMLS_DC);
+ bool addObjectFactory(const std::string&, zval* TSRMLS_DC);
+ bool findObjectFactory(const std::string&, zval* TSRMLS_DC);
+ void destroyObjectFactories(TSRMLS_D);
+
+ const ActiveCommunicatorPtr ac;
+ const zval zv;
+ ObjectFactoryMap objectFactories;
+};
+typedef IceUtil::Handle<CommunicatorInfoI> CommunicatorInfoIPtr;
//
-// Function entries for Ice::Communicator methods.
+// 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:
//
-static function_entry _methods[] =
-{
- {"__construct", PHP_FN(Ice_Communicator___construct), 0},
- {"getProperty", PHP_FN(Ice_Communicator_getProperty), 0},
- {"setProperty", PHP_FN(Ice_Communicator_setProperty), 0},
- {"stringToProxy", PHP_FN(Ice_Communicator_stringToProxy), 0},
- {"proxyToString", PHP_FN(Ice_Communicator_proxyToString), 0},
- {"propertyToProxy", PHP_FN(Ice_Communicator_propertyToProxy), 0},
- {"stringToIdentity", PHP_FN(Ice_Communicator_stringToIdentity), 0},
- {"identityToString", PHP_FN(Ice_Communicator_identityToString), 0},
- {"addObjectFactory", PHP_FN(Ice_Communicator_addObjectFactory), 0},
- {"findObjectFactory", PHP_FN(Ice_Communicator_findObjectFactory), 0},
- {"flushBatchRequests", PHP_FN(Ice_Communicator_flushBatchRequests), 0},
- {0, 0, 0}
+// * 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.
+//
+class ObjectFactoryI : public Ice::ObjectFactory
+{
+public:
+
+ ObjectFactoryI(const Ice::CommunicatorPtr&);
+
+ virtual Ice::ObjectPtr create(const std::string&);
+ virtual void destroy();
+
+private:
+
+ Ice::CommunicatorPtr _communicator;
};
-bool
-IcePHP::communicatorInit(TSRMLS_D)
+class ReaperTask : public IceUtil::TimerTask
{
- //
- // Register the Ice_Communicator class.
- //
- zend_class_entry ce;
- INIT_CLASS_ENTRY(ce, "Ice_Communicator", _methods);
- ce.create_object = handleAlloc;
- _communicatorClassEntry = zend_register_internal_class(&ce TSRMLS_CC);
- memcpy(&_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- _handlers.clone_obj = handleClone;
- _handlers.get_method = handleGetMethod;
+public:
+
+ virtual void runTimerTask();
+};
- return true;
}
-bool
-IcePHP::createCommunicator(TSRMLS_D)
+//
+// Communicator support.
+//
+static zend_object_handlers _handlers;
+
+//
+// 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.
+//
+typedef map<string, Ice::PropertiesPtr> ProfileMap;
+static ProfileMap _profiles;
+static const string _defaultProfileName = "";
+
+//
+// This map represents communicators that have been registered so that they can be used
+// by multiple PHP requests.
+//
+typedef map<string, ActiveCommunicatorPtr> RegisteredCommunicatorMap;
+static RegisteredCommunicatorMap _registeredCommunicators;
+static IceUtil::StaticMutex _registeredCommunicatorsMutex = ICE_STATIC_MUTEX_INITIALIZER;
+
+static IceUtil::TimerPtr _timer;
+
+//
+// This map is stored in the "global" variables for each PHP request and holds
+// the communicators that have been created (or registered communicators that have
+// been used) by the request.
+//
+typedef map<Ice::CommunicatorPtr, CommunicatorInfoIPtr> CommunicatorMap;
+
+extern "C"
{
- zval* global;
- MAKE_STD_ZVAL(global);
+static zend_object_value handleAlloc(zend_class_entry* TSRMLS_DC);
+static void handleFreeStorage(void* TSRMLS_DC);
+static zend_object_value handleClone(zval* TSRMLS_DC);
+}
+
+ZEND_METHOD(Ice_Communicator, __construct)
+{
+ runtimeError("communicators cannot be instantiated directly" TSRMLS_CC);
+}
+
+ZEND_METHOD(Ice_Communicator, destroy)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
//
- // Create the global variable for the communicator, but delay creation of the communicator
- // itself until it is first used (see handleGetMethod).
+ // Remove all registrations.
//
- if(object_init_ex(global, _communicatorClassEntry) != SUCCESS)
{
- php_error_docref(0 TSRMLS_CC, E_ERROR, "unable to create object for communicator");
- return false;
+ IceUtil::StaticMutex::Lock sync(_registeredCommunicatorsMutex);
+ for(vector<string>::iterator p = _this->ac->ids.begin(); p != _this->ac->ids.end(); ++p)
+ {
+ _registeredCommunicators.erase(*p);
+ }
+ _this->ac->ids.clear();
}
//
- // Register the global variable "ICE" to hold the communicator.
+ // We need to destroy any object factories installed by this request.
//
- ICE_G(communicator) = global;
- ZEND_SET_GLOBAL_VAR("ICE", global);
+ _this->destroyObjectFactories(TSRMLS_C);
- return true;
+ Ice::CommunicatorPtr c = _this->getCommunicator();
+ assert(c);
+ CommunicatorMap* m = reinterpret_cast<CommunicatorMap*>(ICE_G(communicatorMap));
+ assert(m);
+ assert(m->find(c) != m->end());
+ m->erase(c);
+
+ try
+ {
+ c->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
}
-Ice::CommunicatorPtr
-IcePHP::getCommunicator(TSRMLS_D)
+ZEND_METHOD(Ice_Communicator, stringToProxy)
{
- Ice::CommunicatorPtr result;
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
- void* data;
- if(zend_hash_find(&EG(symbol_table), "ICE", sizeof("ICE"), &data) == SUCCESS)
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &strLen) != SUCCESS)
{
- zval** zv = reinterpret_cast<zval**>(data);
- ice_object* obj = getObject(*zv TSRMLS_CC);
- assert(obj);
+ RETURN_NULL();
+ }
+ string s(str, strLen);
- //
- // Initialize the communicator if necessary.
- //
- if(!obj->ptr)
+ try
+ {
+ Ice::ObjectPrx prx = _this->getCommunicator()->stringToProxy(s);
+ if(!createProxy(return_value, prx, _this TSRMLS_CC))
{
- try
- {
- initCommunicator(obj TSRMLS_CC);
- }
- catch(const IceUtil::Exception& ex)
- {
- ostringstream ostr;
- ex.ice_print(ostr);
- php_error_docref(0 TSRMLS_CC, E_ERROR, "unable to initialize communicator:\n%s", ostr.str().c_str());
- return 0;
- }
+ RETURN_NULL();
}
-
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
- result = *_this;
}
-
- return result;
-}
-
-zval*
-IcePHP::getCommunicatorZval(TSRMLS_D)
-{
- void* data = 0;
- zend_hash_find(&EG(symbol_table), "ICE", sizeof("ICE"), &data);
- assert(data);
- zval **zv = reinterpret_cast<zval**>(data);
- return *zv;
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
}
-ZEND_FUNCTION(Ice_Communicator___construct)
+ZEND_METHOD(Ice_Communicator, proxyToString)
{
- php_error_docref(0 TSRMLS_CC, E_ERROR, "Ice_Communicator cannot be instantiated, use the global variable $ICE");
-}
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
-ZEND_FUNCTION(Ice_Communicator_getProperty)
-{
- if(ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2)
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &zv, proxyClassEntry) != SUCCESS)
{
- WRONG_PARAM_COUNT;
+ RETURN_NULL();
}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ try
{
- return;
+ string str;
+ if(zv)
+ {
+ Ice::ObjectPrx prx;
+ ClassInfoPtr info;
+ if(!fetchProxy(zv, prx, info TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ assert(prx);
+ str = prx->ice_toString();
+ }
+ RETURN_STRINGL(STRCAST(str.c_str()), str.length(), 1);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+}
- char *name;
- int nameLen;
- char *def = 0;
- int defLen = 0;
+ZEND_METHOD(Ice_Communicator, propertyToProxy)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &name, &nameLen, &def, &defLen) == FAILURE)
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &strLen) != SUCCESS)
{
RETURN_NULL();
}
+ string s(str, strLen);
try
{
- string val = (*_this)->getProperties()->getProperty(name);
- if(val.empty() && def)
- {
- RETURN_STRING(def, 1);
- }
- else
+ Ice::ObjectPrx prx = _this->getCommunicator()->propertyToProxy(s);
+ if(!createProxy(return_value, prx, _this TSRMLS_CC))
{
- RETURN_STRING(const_cast<char*>(val.c_str()), 1);
+ RETURN_NULL();
}
}
catch(const IceUtil::Exception& ex)
{
throwException(ex TSRMLS_CC);
- RETURN_EMPTY_STRING();
+ RETURN_NULL();
}
}
-ZEND_FUNCTION(Ice_Communicator_setProperty)
+ZEND_METHOD(Ice_Communicator, stringToIdentity)
{
- if(ZEND_NUM_ARGS() != 2)
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &strLen) != SUCCESS)
{
- WRONG_PARAM_COUNT;
+ RETURN_NULL();
}
+ string s(str, strLen);
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ try
{
- return;
+ Ice::Identity id = _this->getCommunicator()->stringToIdentity(s);
+ if(!createIdentity(return_value, id TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
+}
+
+ZEND_METHOD(Ice_Communicator, identityToString)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
- char *prop;
- int propLen;
- char *val;
- int valLen;
+ zend_class_entry* identityClass = idToClass("::Ice::Identity" TSRMLS_CC);
+ assert(identityClass);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prop, &propLen, &val, &valLen) == FAILURE)
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zv, identityClass) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+ Ice::Identity id;
+ if(!extractIdentity(zv, id TSRMLS_CC))
{
RETURN_NULL();
}
try
{
- (*_this)->getProperties()->setProperty(prop, val);
+ string str = _this->getCommunicator()->identityToString(id);
+ RETURN_STRINGL(STRCAST(str.c_str()), str.length(), 1);
}
catch(const IceUtil::Exception& ex)
{
throwException(ex TSRMLS_CC);
+ RETURN_NULL();
}
- RETURN_EMPTY_STRING();
}
-ZEND_FUNCTION(Ice_Communicator_stringToProxy)
+ZEND_METHOD(Ice_Communicator, addObjectFactory)
{
- if(ZEND_NUM_ARGS() != 1)
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ zend_class_entry* factoryClass = idToClass("Ice::ObjectFactory" TSRMLS_CC);
+ assert(factoryClass);
+
+ zval* factory;
+ char* id;
+ int idLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os!", &factory, factoryClass, &id, &idLen TSRMLS_CC) !=
+ SUCCESS)
{
- WRONG_PARAM_COUNT;
+ RETURN_NULL();
}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ string type;
+ if(id)
{
- return;
+ type = string(id, idLen);
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
-
- char *str;
- int len;
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE)
+ if(!_this->addObjectFactory(type, factory TSRMLS_CC))
{
RETURN_NULL();
}
+}
- Ice::ObjectPrx proxy;
- try
+ZEND_METHOD(Ice_Communicator, findObjectFactory)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ char* id;
+ int idLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &id, &idLen TSRMLS_CC) != SUCCESS)
{
- proxy = (*_this)->stringToProxy(str);
+ RETURN_NULL();
}
- catch(const IceUtil::Exception& ex)
+
+ string type;
+ if(id)
{
- throwException(ex TSRMLS_CC);
- RETURN_NULL();
+ type = string(id, idLen);
}
- if(!createProxy(return_value, proxy TSRMLS_CC))
+ if(!_this->findObjectFactory(type, return_value TSRMLS_CC))
{
RETURN_NULL();
}
}
-ZEND_FUNCTION(Ice_Communicator_proxyToString)
+ZEND_METHOD(Ice_Communicator, getImplicitContext)
{
- if(ZEND_NUM_ARGS() != 1)
- {
- WRONG_PARAM_COUNT;
- }
+ runtimeError("not implemented" TSRMLS_CC);
+}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ZEND_METHOD(Ice_Communicator, getProperties)
+{
+ if(ZEND_NUM_ARGS() > 0)
{
- return;
+ WRONG_PARAM_COUNT;
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
- zval* zprx;
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &zprx, proxyClassEntry) == FAILURE)
+ try
{
- RETURN_EMPTY_STRING();
+ Ice::PropertiesPtr props = _this->getCommunicator()->getProperties();
+ if(!createProperties(return_value, props TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
}
-
- Ice::ObjectPrx proxy;
- Slice::ClassDefPtr def;
- if(!zprx || !fetchProxy(zprx, proxy, def TSRMLS_CC))
+ catch(const IceUtil::Exception& ex)
{
- RETURN_EMPTY_STRING();
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
}
+}
+
+ZEND_METHOD(Ice_Communicator, getLogger)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
try
{
- string result = (*_this)->proxyToString(proxy);
- RETURN_STRING(const_cast<char*>(result.c_str()), 1);
+ Ice::LoggerPtr logger = _this->getCommunicator()->getLogger();
+ if(!createLogger(return_value, logger TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
}
catch(const IceUtil::Exception& ex)
{
throwException(ex TSRMLS_CC);
- RETURN_EMPTY_STRING();
+ RETURN_NULL();
}
}
-ZEND_FUNCTION(Ice_Communicator_propertyToProxy)
+ZEND_METHOD(Ice_Communicator, getDefaultRouter)
{
- if(ZEND_NUM_ARGS() != 1)
+ if(ZEND_NUM_ARGS() > 0)
{
WRONG_PARAM_COUNT;
}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ try
{
- return;
+ Ice::RouterPrx router = _this->getCommunicator()->getDefaultRouter();
+ if(router)
+ {
+ ClassInfoPtr info = getClassInfoById("::Ice::Router" TSRMLS_CC);
+ if(!info)
+ {
+ runtimeError("no definition for Ice::Router" TSRMLS_CC);
+ RETURN_NULL();
+ }
+ if(!createProxy(return_value, router, info, _this TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ }
+ else
+ {
+ RETURN_NULL();
+ }
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
+}
- char *str;
- int len;
+ZEND_METHOD(Ice_Communicator, setDefaultRouter)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE)
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &zv, proxyClassEntry TSRMLS_CC) != SUCCESS)
{
RETURN_NULL();
}
Ice::ObjectPrx proxy;
+ ClassInfoPtr info;
+ if(zv && !fetchProxy(zv, proxy, info TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+
try
{
- proxy = (*_this)->propertyToProxy(str);
+ Ice::RouterPrx router;
+ if(proxy)
+ {
+ if(!info || !info->isA("::Ice::Router"))
+ {
+ invalidArgument("setDefaultRouter requires a proxy narrowed to Ice::Router" TSRMLS_CC);
+ RETURN_NULL();
+ }
+ router = Ice::RouterPrx::uncheckedCast(proxy);
+ }
+ _this->getCommunicator()->setDefaultRouter(router);
}
catch(const IceUtil::Exception& ex)
{
throwException(ex TSRMLS_CC);
RETURN_NULL();
}
-
- if(!createProxy(return_value, proxy TSRMLS_CC))
- {
- RETURN_NULL();
- }
}
-ZEND_FUNCTION(Ice_Communicator_identityToString)
+ZEND_METHOD(Ice_Communicator, getDefaultLocator)
{
- if(ZEND_NUM_ARGS() != 1)
+ if(ZEND_NUM_ARGS() > 0)
{
WRONG_PARAM_COUNT;
}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ try
+ {
+ Ice::LocatorPrx locator = _this->getCommunicator()->getDefaultLocator();
+ if(locator)
+ {
+ ClassInfoPtr info = getClassInfoById("::Ice::Locator" TSRMLS_CC);
+ if(!info)
+ {
+ runtimeError("no definition for Ice::Locator" TSRMLS_CC);
+ RETURN_NULL();
+ }
+ if(!createProxy(return_value, locator, info, _this TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ }
+ else
+ {
+ RETURN_NULL();
+ }
+ }
+ catch(const IceUtil::Exception& ex)
{
- return;
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+}
- zend_class_entry* cls = findClass("Ice_Identity" TSRMLS_CC);
- assert(cls);
+ZEND_METHOD(Ice_Communicator, setDefaultLocator)
+{
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
- zval *zid;
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &zv, proxyClassEntry TSRMLS_CC) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zid, cls) == FAILURE)
+ Ice::ObjectPrx proxy;
+ ClassInfoPtr info;
+ if(zv && !fetchProxy(zv, proxy, info TSRMLS_CC))
{
RETURN_NULL();
}
- Ice::Identity id;
- if(extractIdentity(zid, id TSRMLS_CC))
+ try
{
- string s = (*_this)->identityToString(id);
- RETURN_STRINGL(const_cast<char*>(s.c_str()), s.length(), 1);
+ Ice::LocatorPrx locator;
+ if(proxy)
+ {
+ if(!info || !info->isA("::Ice::Locator"))
+ {
+ invalidArgument("setDefaultRouter requires a proxy narrowed to Ice::Locator" TSRMLS_CC);
+ RETURN_NULL();
+ }
+ locator = Ice::LocatorPrx::uncheckedCast(proxy);
+ }
+ _this->getCommunicator()->setDefaultLocator(locator);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
}
}
-ZEND_FUNCTION(Ice_Communicator_stringToIdentity)
+ZEND_METHOD(Ice_Communicator, flushBatchRequests)
{
- if(ZEND_NUM_ARGS() != 1)
+ CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ if(ZEND_NUM_ARGS() != 8)
{
WRONG_PARAM_COUNT;
}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ try
{
- return;
+ _this->getCommunicator()->flushBatchRequests();
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
-
- char* str;
- int len;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE)
+ catch(const IceUtil::Exception& ex)
{
+ throwException(ex TSRMLS_CC);
RETURN_NULL();
}
+}
+
+#ifdef _WIN32
+extern "C"
+#endif
+static zend_object_value
+handleAlloc(zend_class_entry* ce TSRMLS_DC)
+{
+ zend_object_value result;
+
+ Wrapper<CommunicatorInfoIPtr>* obj = Wrapper<CommunicatorInfoIPtr>::create(ce TSRMLS_CC);
+ assert(obj);
+
+ result.handle = zend_objects_store_put(obj, 0, (zend_objects_free_object_storage_t)handleFreeStorage, 0 TSRMLS_CC);
+ result.handlers = &_handlers;
+ return result;
+}
+
+#ifdef _WIN32
+extern "C"
+#endif
+static void
+handleFreeStorage(void* p TSRMLS_DC)
+{
+ Wrapper<CommunicatorInfoIPtr>* obj = static_cast<Wrapper<CommunicatorInfoIPtr>*>(p);
+ delete obj->ptr;
+ zend_objects_free_object_storage(static_cast<zend_object*>(p) TSRMLS_CC);
+}
+
+#ifdef _WIN32
+extern "C"
+#endif
+static zend_object_value
+handleClone(zval* zv TSRMLS_DC)
+{
+ php_error_docref(0 TSRMLS_CC, E_ERROR, "communicators cannot be cloned");
+ return zend_object_value();
+}
+
+static CommunicatorInfoIPtr
+createCommunicator(zval* zv, const ActiveCommunicatorPtr& ac TSRMLS_DC)
+{
try
{
- Ice::Identity id = (*_this)->stringToIdentity(str);
- createIdentity(return_value, id TSRMLS_CC);
+ if(object_init_ex(zv, communicatorClassEntry) != SUCCESS)
+ {
+ runtimeError("unable to initialize communicator object" TSRMLS_CC);
+ return 0;
+ }
+
+ Wrapper<CommunicatorInfoIPtr>* obj = Wrapper<CommunicatorInfoIPtr>::extract(zv TSRMLS_CC);
+ assert(!obj->ptr);
+
+ CommunicatorInfoIPtr info = new CommunicatorInfoI(ac, zv);
+ obj->ptr = new CommunicatorInfoIPtr(info);
+
+ CommunicatorMap* m;
+ if(ICE_G(communicatorMap))
+ {
+ m = reinterpret_cast<CommunicatorMap*>(ICE_G(communicatorMap));
+ }
+ else
+ {
+ m = new CommunicatorMap;
+ ICE_G(communicatorMap) = m;
+ }
+ m->insert(CommunicatorMap::value_type(ac->communicator, info));
+
+ return info;
}
catch(const IceUtil::Exception& ex)
{
throwException(ex TSRMLS_CC);
+ return 0;
}
}
-ZEND_FUNCTION(Ice_Communicator_addObjectFactory)
+static CommunicatorInfoIPtr
+initializeCommunicator(zval* zv, Ice::StringSeq& args, const Ice::InitializationData& initData TSRMLS_DC)
{
- if(ZEND_NUM_ARGS() != 2)
+ try
{
- WRONG_PARAM_COUNT;
+ Ice::CommunicatorPtr c = Ice::initialize(args, initData);
+ ActiveCommunicatorPtr ac = new ActiveCommunicator(c);
+
+ //
+ // Install a default object factory that delegates to PHP factories.
+ //
+ c->addObjectFactory(new ObjectFactoryI(c), "");
+
+ CommunicatorInfoIPtr info = createCommunicator(zv, ac TSRMLS_CC);
+ if(!info)
+ {
+ try
+ {
+ c->destroy();
+ }
+ catch(...)
+ {
+ }
+ }
+
+ return info;
}
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ return 0;
+ }
+}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ZEND_FUNCTION(Ice_initialize)
+{
+ if(ZEND_NUM_ARGS() > 2)
{
- return;
+ runtimeError("too many arguments" TSRMLS_CC);
+ RETURN_NULL();
}
- assert(obj->ptr);
- zval* zfactory;
- char* id;
- int len;
+ zend_class_entry* initClass = idToClass("::Ice::InitializationData" TSRMLS_CC);
+ assert(initClass);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "os", &zfactory, &id, &len) == FAILURE)
+ //
+ // Retrieve the arguments.
+ //
+ zval*** args = static_cast<zval***>(emalloc(ZEND_NUM_ARGS() * sizeof(zval**)));
+ AutoEfree autoArgs(args); // Call efree on return
+ if(zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE)
{
- return;
+ runtimeError("unable to get arguments" TSRMLS_CC);
+ RETURN_NULL();
}
+ Ice::StringSeq seq;
+ Ice::InitializationData initData;
+ zval* zvinit = 0;
+
//
- // Verify that the object implements Ice_ObjectFactory.
+ // Accept the following invocations:
//
- // TODO: When zend_check_class is changed to also check interfaces, we can remove this code and
- // pass the class entry for Ice_ObjectFactory to zend_parse_parameters instead.
+ // initialize(array, InitializationData)
+ // initialize(array)
+ // initialize(InitializationData)
+ // initialize()
//
- zend_class_entry* ce = Z_OBJCE_P(zfactory);
- zend_class_entry* base = findClass("Ice_ObjectFactory" TSRMLS_CC);
- assert(base);
- if(!checkClass(ce, base))
+ if(ZEND_NUM_ARGS())
{
- php_error_docref(0 TSRMLS_CC, E_ERROR, "object does not implement Ice_ObjectFactory");
- return;
+ if(Z_TYPE_PP(args[0]) == IS_ARRAY)
+ {
+ if(!extractStringArray(*args[0], seq TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ if(ZEND_NUM_ARGS() > 1)
+ {
+ if(Z_TYPE_PP(args[1]) != IS_OBJECT || Z_OBJCE_PP(args[1]) != initClass)
+ {
+ string s = zendTypeToString(Z_TYPE_PP(args[1]));
+ invalidArgument("expected InitializationData object but received %s" TSRMLS_CC, s.c_str());
+ RETURN_NULL();
+ }
+ zvinit = *args[1];
+ }
+ }
+ else if(Z_TYPE_PP(args[0]) == IS_OBJECT && Z_OBJCE_PP(args[0]) == initClass)
+ {
+ if(ZEND_NUM_ARGS() > 1)
+ {
+ runtimeError("too many arguments" TSRMLS_CC);
+ RETURN_NULL();
+ }
+ zvinit = *args[0];
+ }
+ else
+ {
+ string s = zendTypeToString(Z_TYPE_PP(args[0]));
+ invalidArgument("unexpected argument type %s" TSRMLS_CC, s.c_str());
+ RETURN_NULL();
+ }
}
- ObjectFactoryMap* ofm = static_cast<ObjectFactoryMap*>(ICE_G(objectFactoryMap));
- ObjectFactoryMap::iterator p = ofm->find(id);
- if(p != ofm->end())
+ if(zvinit)
{
- Ice::AlreadyRegisteredException ex(__FILE__, __LINE__);
- ex.kindOfObject = "object factory";
- ex.id = id;
- throwException(ex TSRMLS_CC);
- return;
- }
+ void* data;
+ string member;
- //
- // Create a new zval with the same object handle as the factory.
- //
- zval* zv;
- MAKE_STD_ZVAL(zv);
- Z_TYPE_P(zv) = IS_OBJECT;
- zv->value.obj = zfactory->value.obj;
+ member = "properties";
+ if(zend_hash_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), member.size() + 1, &data) == SUCCESS)
+ {
+ zval** val = reinterpret_cast<zval**>(data);
+ if(!fetchProperties(*val, initData.properties TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ }
- //
- // Increment the factory's reference count.
- //
- Z_OBJ_HT_P(zv)->add_ref(zv TSRMLS_CC);
+ member = "logger";
+ if(zend_hash_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), member.size() + 1, &data) == SUCCESS)
+ {
+ zval** val = reinterpret_cast<zval**>(data);
+ if(!fetchLogger(*val, initData.logger TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ }
+ }
- //
- // Update the factory map.
- //
- ofm->insert(ObjectFactoryMap::value_type(id, zv));
+ CommunicatorInfoIPtr info = initializeCommunicator(return_value, seq, initData TSRMLS_CC);
+ if(!info)
+ {
+ RETURN_NULL();
+ }
}
-ZEND_FUNCTION(Ice_Communicator_findObjectFactory)
+ZEND_FUNCTION(Ice_register)
{
- if(ZEND_NUM_ARGS() != 1)
+ zval* comm;
+ char* s;
+ int sLen;
+ long expires = 0;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &comm, communicatorClassEntry, &s, &sLen, &expires
+ TSRMLS_CC) != SUCCESS)
{
- WRONG_PARAM_COUNT;
+ RETURN_NULL();
}
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ string id(s, sLen);
+ if(id.empty())
{
+ invalidArgument("communicator id cannot be empty" TSRMLS_CC);
RETURN_NULL();
}
- assert(obj->ptr);
- char* id;
- int len;
+ CommunicatorInfoIPtr info = Wrapper<CommunicatorInfoIPtr>::value(comm TSRMLS_CC);
+ assert(info);
+
+ IceUtil::StaticMutex::Lock sync(_registeredCommunicatorsMutex);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &id, &len) == FAILURE)
+ RegisteredCommunicatorMap::iterator p = _registeredCommunicators.find(id);
+ if(p != _registeredCommunicators.end())
{
- RETURN_NULL();
+ if(p->second->communicator != info->getCommunicator())
+ {
+ //
+ // A different communicator is already registered with that ID.
+ //
+ RETURN_FALSE;
+ }
}
-
- ObjectFactoryMap* ofm = static_cast<ObjectFactoryMap*>(ICE_G(objectFactoryMap));
- ObjectFactoryMap::iterator p = ofm->find(id);
- if(p == ofm->end())
+ else
{
- RETURN_NULL();
+ info->ac->ids.push_back(id);
+ _registeredCommunicators[id] = info->ac;
}
- //
- // Set the zval with the same object handle as the factory.
- //
- Z_TYPE_P(return_value) = IS_OBJECT;
- return_value->value.obj = p->second->value.obj;
+ if(expires > 0)
+ {
+ //
+ // Update the expiration time. If a communicator is registered with multiple IDs, we
+ // always use the most recent expiration setting.
+ //
+ info->ac->expires = static_cast<int>(expires);
+ info->ac->lastAccess = IceUtil::Time::now();
- //
- // Increment the factory's reference count.
- //
- Z_OBJ_HT_P(p->second)->add_ref(p->second TSRMLS_CC);
+ //
+ // Start the timer if necessary. Reap expired communicators every five minutes.
+ //
+ if(!_timer)
+ {
+ _timer = new IceUtil::Timer;
+ _timer->scheduleRepeated(new ReaperTask, IceUtil::Time::seconds(5 * 60));
+ }
+ }
+
+ RETURN_TRUE;
}
-ZEND_FUNCTION(Ice_Communicator_flushBatchRequests)
+ZEND_FUNCTION(Ice_unregister)
{
- if(ZEND_NUM_ARGS() != 0)
- {
- WRONG_PARAM_COUNT;
- }
-
- ice_object* obj = getObject(getThis() TSRMLS_CC);
- if(!obj)
+ char* s;
+ int sLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s, &sLen TSRMLS_CC) != SUCCESS)
{
RETURN_NULL();
}
- assert(obj->ptr);
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
- try
- {
- (*_this)->flushBatchRequests();;
- }
- catch(const IceUtil::Exception& ex)
+ string id(s, sLen);
+
+ IceUtil::StaticMutex::Lock sync(_registeredCommunicatorsMutex);
+
+ RegisteredCommunicatorMap::iterator p = _registeredCommunicators.find(id);
+ if(p == _registeredCommunicators.end())
{
- throwException(ex TSRMLS_CC);
+ //
+ // No communicator registered with that ID.
+ //
+ RETURN_FALSE;
}
+
+ //
+ // Remove the ID from the ActiveCommunicator's list of registered IDs.
+ //
+ ActiveCommunicatorPtr ac = p->second;
+ vector<string>::iterator q = find(ac->ids.begin(), ac->ids.end(), id);
+ assert(q != ac->ids.end());
+ ac->ids.erase(q);
+
+ _registeredCommunicators.erase(p);
+
+ RETURN_TRUE;
}
-ZEND_FUNCTION(Ice_stringToIdentity)
+ZEND_FUNCTION(Ice_find)
{
- if(ZEND_NUM_ARGS() != 1)
+ char* s;
+ int sLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s, &sLen TSRMLS_CC) != SUCCESS)
{
- WRONG_PARAM_COUNT;
+ RETURN_NULL();
}
- char* str;
- int len;
+ string id(s, sLen);
+
+ IceUtil::StaticMutex::Lock sync(_registeredCommunicatorsMutex);
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE)
+ RegisteredCommunicatorMap::iterator p = _registeredCommunicators.find(id);
+ if(p == _registeredCommunicators.end())
{
+ //
+ // No communicator registered with that ID.
+ //
RETURN_NULL();
}
- try
+ if(p->second->expires > 0)
{
- Ice::CommunicatorPtr communicator = getCommunicator(TSRMLS_C);
- Ice::Identity id = communicator->stringToIdentity(str);
- createIdentity(return_value, id TSRMLS_CC);
+ p->second->lastAccess = IceUtil::Time::now();
}
- catch(const IceUtil::Exception& ex)
+
+ //
+ // Check if this communicator has already been obtained by the current request.
+ // If so, we can return the existing PHP object that corresponds to the communicator.
+ //
+ CommunicatorMap* m = reinterpret_cast<CommunicatorMap*>(ICE_G(communicatorMap));
+ if(m)
{
- throwException(ex TSRMLS_CC);
+ CommunicatorMap::iterator q = m->find(p->second->communicator);
+ if(q != m->end())
+ {
+ q->second->getZval(return_value TSRMLS_CC);
+ return;
+ }
+ }
+
+ if(!createCommunicator(return_value, p->second TSRMLS_CC))
+ {
+ RETURN_NULL();
}
}
-ZEND_FUNCTION(Ice_identityToString)
+ZEND_FUNCTION(Ice_getProperties)
{
- if(ZEND_NUM_ARGS() != 1)
+ char* s = 0;
+ int sLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &s, &sLen TSRMLS_CC) != SUCCESS)
{
- WRONG_PARAM_COUNT;
+ RETURN_NULL();
}
- zend_class_entry* cls = findClass("Ice_Identity" TSRMLS_CC);
- assert(cls);
-
- zval *zid;
+ string name;
+ if(s)
+ {
+ name = string(s, sLen);
+ }
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zid, cls) == FAILURE)
+ ProfileMap::iterator p = _profiles.find(name);
+ if(p == _profiles.end())
{
RETURN_NULL();
}
- Ice::Identity id;
- if(extractIdentity(zid, id TSRMLS_CC))
+ Ice::PropertiesPtr clone = p->second->clone();
+ if(!createProperties(return_value, clone TSRMLS_CC))
{
- Ice::CommunicatorPtr communicator = getCommunicator(TSRMLS_C);
- string s = communicator->identityToString(id);
- RETURN_STRINGL(const_cast<char*>(s.c_str()), s.length(), 1);
+ RETURN_NULL();
}
}
-#ifdef _WIN32
-extern "C"
-#endif
-static zend_object_value
-handleAlloc(zend_class_entry* ce TSRMLS_DC)
+//
+// Predefined methods for Communicator.
+//
+static function_entry _interfaceMethods[] =
{
- zend_object_value result;
-
- ice_object* obj = newObject(ce TSRMLS_CC);
- assert(obj);
+ {0, 0, 0}
+};
+static 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, 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)
+ {0, 0, 0}
+};
- result.handle = zend_objects_store_put(obj, 0, (zend_objects_free_object_storage_t)handleFreeStorage, 0 TSRMLS_CC);
- result.handlers = &_handlers;
+static bool
+createProfile(const string& name, const string& config, const string& options TSRMLS_DC)
+{
+ ProfileMap::iterator p = _profiles.find(name);
+ if(p != _profiles.end())
+ {
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "duplicate Ice profile `%s'", name.c_str());
+ return false;
+ }
- return result;
-}
+ Ice::PropertiesPtr properties = Ice::createProperties();
-#ifdef _WIN32
-extern "C"
-#endif
-static zend_object_value
-handleClone(zval* zv TSRMLS_DC)
-{
- zend_object_value result;
- memset(&result, 0, sizeof(zend_object_value));
- php_error_docref(0 TSRMLS_CC, E_ERROR, "__clone is not supported for Ice_Communicator");
- return result;
-}
+ if(!config.empty())
+ {
+ try
+ {
+ properties->load(config);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ ostringstream ostr;
+ ex.ice_print(ostr);
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "unable to load Ice configuration file %s:\n%s", config.c_str(),
+ ostr.str().c_str());
+ return false;
+ }
+ }
-#ifdef _WIN32
-extern "C"
-#endif
-static void
-handleFreeStorage(void* p TSRMLS_DC)
-{
- ice_object* obj = static_cast<ice_object*>(p);
- if(obj->ptr)
+ if(!options.empty())
{
- Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+ vector<string> args;
try
{
- (*_this)->destroy();
+ args = IceUtilInternal::Options::split(options);
}
catch(const IceUtil::Exception& ex)
{
ostringstream ostr;
ex.ice_print(ostr);
- php_error_docref(0 TSRMLS_CC, E_ERROR, "unable to destroy communicator:\n%s", ostr.str().c_str());
+ string msg = ostr.str();
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "error occurred while parsing the options `%s':\n%s",
+ options.c_str(), msg.c_str());
+ return false;
}
- delete _this;
+
+ properties->parseCommandLineOptions("", args);
}
- zend_objects_free_object_storage(reinterpret_cast<zend_object*>(p) TSRMLS_CC);
+ _profiles[name] = properties;
+ return true;
}
-#ifdef _WIN32
-extern "C"
-#endif
-static union _zend_function*
-handleGetMethod(zval** zv, char* method, int len TSRMLS_DC)
+static bool
+parseProfiles(const string& file TSRMLS_DC)
{
//
- // Delegate to the standard implementation of get_method. We're simply using this hook
- // as a convenient way of implementing lazy initialization of the communicator.
+ // The Zend engine doesn't export a function for loading an INI file, so we
+ // have to do it ourselves. The format is:
+ //
+ // [profile-name]
+ // ice.config = config-file
+ // ice.options = args
//
- zend_function* result = zend_get_std_object_handlers()->get_method(zv, method, len TSRMLS_CC);
- if(result)
+ ifstream in(file.c_str());
+ if(!in)
{
- ice_object* obj = static_cast<ice_object*>(zend_object_store_get_object(*zv TSRMLS_CC));
- if(!obj->ptr)
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "unable to open Ice profiles in %s", file.c_str());
+ return false;
+ }
+
+ string name, config, options;
+ char line[1024];
+ while(in.getline(line, 1024))
+ {
+ const string delim = " \t\r\n";
+ string s = line;
+
+ string::size_type idx = s.find(';');
+ if(idx != string::npos)
+ {
+ s.erase(idx);
+ }
+
+ idx = s.find_last_not_of(delim);
+ if(idx != string::npos && idx + 1 < s.length())
+ {
+ s.erase(idx + 1);
+ }
+
+ string::size_type beg = s.find_first_not_of(delim);
+ if(beg == string::npos)
{
- if(!ICE_G(profile))
+ continue;
+ }
+
+ if(s[beg] == '[')
+ {
+ beg++;
+ string::size_type end = s.find_first_of(" \t]", beg);
+ if(end == string::npos || s[s.length() - 1] != ']')
{
- php_error_docref(0 TSRMLS_CC, E_ERROR, "$ICE used before a profile was loaded");
- return 0;
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "invalid profile section in file %s:\n%s\n", file.c_str(),
+ line);
+ return false;
}
- try
+ if(!name.empty())
{
- initCommunicator(obj TSRMLS_CC);
+ createProfile(name, config, options TSRMLS_CC);
+ config.clear();
+ options.clear();
}
- catch(const IceUtil::Exception& ex)
+
+ name = s.substr(beg, end - beg);
+ }
+ else
+ {
+ string::size_type end = s.find_first_of(delim + "=", beg);
+ assert(end != string::npos);
+
+ string key = s.substr(beg, end - beg);
+
+ end = s.find('=', end);
+ if(end == string::npos)
+ {
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "invalid profile entry in file %s:\n%s\n", file.c_str(), line);
+ return false;
+ }
+ ++end;
+
+ string value;
+ beg = s.find_first_not_of(delim, end);
+ if(beg != string::npos)
+ {
+ end = s.length();
+ value = s.substr(beg, end - beg);
+ }
+
+ if(key == "config" || key == "ice.config")
+ {
+ config = value;
+ }
+ else if(key == "options" || key == "ice.options")
+ {
+ options = value;
+ }
+ else
+ {
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "unknown profile entry in file %s:\n%s\n", file.c_str(), line);
+ }
+
+ if(name.empty())
{
- ostringstream ostr;
- ex.ice_print(ostr);
- php_error_docref(0 TSRMLS_CC, E_ERROR, "unable to initialize communicator:\n%s", ostr.str().c_str());
- return 0;
+ php_error_docref(0 TSRMLS_CC, E_WARNING, "no section for profile entry in file %s:\n%s\n", file.c_str(),
+ line);
+ return false;
}
}
}
- return result;
+ if(!name.empty())
+ {
+ if(!createProfile(name, config, options TSRMLS_CC))
+ {
+ return false;
+ }
+ }
+
+ return true;
}
-//
-// Initialize a communicator instance and store it in the given object. Can raise exceptions.
-//
-static void
-initCommunicator(ice_object* obj TSRMLS_DC)
+bool
+IcePHP::communicatorInit(TSRMLS_D)
{
- assert(!obj->ptr);
+ //
+ // We register an interface and a class that implements the interface. This allows
+ // applications to safely include the Slice-generated code for the type.
+ //
+
+ //
+ // Register the Communicator interface.
+ //
+ zend_class_entry ce;
+#ifdef ICEPHP_USE_NAMESPACES
+ INIT_NS_CLASS_ENTRY(ce, STRCAST("Ice"), STRCAST("Communicator"), _interfaceMethods);
+#else
+ INIT_CLASS_ENTRY(ce, "Ice_Communicator", _interfaceMethods);
+#endif
+ zend_class_entry* interface = zend_register_internal_interface(&ce TSRMLS_CC);
- Ice::PropertiesPtr* properties = static_cast<Ice::PropertiesPtr*>(ICE_G(properties));
+ //
+ // Register the Communicator class.
+ //
+ INIT_CLASS_ENTRY(ce, "IcePHP_Communicator", _classMethods);
+ ce.create_object = handleAlloc;
+ communicatorClassEntry = zend_register_internal_class(&ce TSRMLS_CC);
+ memcpy(&_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ _handlers.clone_obj = handleClone;
+ zend_class_implements(communicatorClassEntry TSRMLS_CC, 1, interface);
- Ice::InitializationData initData;
- initData.properties = *properties;
- Ice::CommunicatorPtr communicator = Ice::initialize(initData);
- obj->ptr = new Ice::CommunicatorPtr(communicator);
+ //
+ // Create the profiles from configuration settings.
+ //
+ const char* config = INI_STR("ice.config");
+ const char* options = INI_STR("ice.options");
+ if(!createProfile(_defaultProfileName, config, options TSRMLS_CC))
+ {
+ return false;
+ }
+
+ const char* profiles = INI_STR("ice.profiles");
+ if(strlen(profiles) > 0)
+ {
+ if(!parseProfiles(profiles TSRMLS_CC))
+ {
+ return false;
+ }
+
+ if(INI_BOOL("ice.hide_profiles"))
+ {
+ memset(const_cast<char*>(profiles), '*', strlen(profiles));
+ //
+ // For some reason the code below does not work as expected. It causes a call
+ // to ini_get_all() to segfault.
+ //
+ /*
+ if(zend_alter_ini_entry("ice.profiles", sizeof("ice.profiles"), "<hidden>", sizeof("<hidden>") - 1,
+ PHP_INI_ALL, PHP_INI_STAGE_STARTUP) == FAILURE)
+ {
+ return false;
+ }
+ */
+ }
+ }
+
+ return true;
+}
+
+bool
+IcePHP::communicatorShutdown(TSRMLS_D)
+{
+ _profiles.clear();
+
+ IceUtil::StaticMutex::Lock sync(_registeredCommunicatorsMutex);
+
+ if(_timer)
+ {
+ _timer->destroy();
+ _timer = 0;
+ }
+
+ //
+ // Clearing the map releases the last remaining reference counts of the ActiveCommunicator
+ // objects. The ActiveCommunicator destructor destroys its communicator.
+ //
+ _registeredCommunicators.clear();
+
+ return true;
+}
+
+bool
+IcePHP::communicatorRequestInit(TSRMLS_D)
+{
+ ICE_G(communicatorMap) = 0;
+
+ return true;
+}
+
+bool
+IcePHP::communicatorRequestShutdown(TSRMLS_D)
+{
+ if(ICE_G(communicatorMap))
+ {
+ CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap));
+ for(CommunicatorMap::iterator p = m->begin(); p != m->end(); ++p)
+ {
+ CommunicatorInfoIPtr info = p->second;
+
+ //
+ // We need to destroy any object factories installed during this request.
+ //
+ info->destroyObjectFactories(TSRMLS_C);
+ }
+
+ //
+ // Deleting the map decrements the reference count of its ActiveCommunicator
+ // values. If there are no other references to an ActiveCommunicator, its
+ // destructor destroys the communicator.
+ //
+ delete m;
+ }
+
+ return true;
+}
+
+IcePHP::ActiveCommunicator::ActiveCommunicator(const Ice::CommunicatorPtr& c) :
+ communicator(c), expires(0)
+{
+}
+IcePHP::ActiveCommunicator::~ActiveCommunicator()
+{
//
- // Register our default object factory with the communicator.
+ // There are no more references to this communicator, so we can safely destroy it now.
//
- Ice::ObjectFactoryPtr factory = new PHPObjectFactory(TSRMLS_C);
- communicator->addObjectFactory(factory, "");
+ try
+ {
+ communicator->destroy();
+ }
+ catch(...)
+ {
+ }
+}
+
+IcePHP::CommunicatorInfoI::CommunicatorInfoI(const ActiveCommunicatorPtr& c, zval* z) :
+ ac(c),
+ zv(*z) // This is legal - it simply copies the object's handle.
+{
+}
+
+void
+IcePHP::CommunicatorInfoI::getZval(zval* z TSRMLS_DC)
+{
+ Z_TYPE_P(z) = IS_OBJECT;
+ z->value.obj = zv.value.obj;
+ addRef(TSRMLS_C);
+}
+
+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::addObjectFactory(const string& id, zval* factory TSRMLS_DC)
+{
+ ObjectFactoryMap::iterator p = objectFactories.find(id);
+ if(p != objectFactories.end())
+ {
+ Ice::AlreadyRegisteredException ex(__FILE__, __LINE__);
+ ex.kindOfObject = "object factory";
+ ex.id = id;
+ throwException(ex TSRMLS_CC);
+ return false;
+ }
+
+ objectFactories.insert(ObjectFactoryMap::value_type(id, factory));
+ Z_ADDREF_P(factory);
+
+ return true;
+}
+
+bool
+IcePHP::CommunicatorInfoI::findObjectFactory(const string& id, zval* zv TSRMLS_DC)
+{
+ ObjectFactoryMap::iterator p = objectFactories.find(id);
+ if(p != objectFactories.end())
+ {
+ *zv = *p->second; // This is legal - it simply copies the object's handle.
+ INIT_PZVAL(zv);
+ zval_copy_ctor(zv);
+ return true;
+ }
+
+ return false;
+}
+
+void
+IcePHP::CommunicatorInfoI::destroyObjectFactories(TSRMLS_D)
+{
+ for(ObjectFactoryMap::iterator p = objectFactories.begin(); p != objectFactories.end(); ++p)
+ {
+ //
+ // Invoke the destroy method on each registered PHP factory.
+ //
+ invokeMethod(p->second, "destroy" TSRMLS_CC);
+ zend_clear_exception(TSRMLS_C);
+ zval_ptr_dtor(&p->second);
+ }
+}
+
+IcePHP::ObjectFactoryI::ObjectFactoryI(const Ice::CommunicatorPtr& communicator) :
+ _communicator(communicator)
+{
+}
+
+Ice::ObjectPtr
+IcePHP::ObjectFactoryI::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())
+ {
+ q = info->objectFactories.find(""); // Look for a default factory.
+ }
+ if(q != info->objectFactories.end())
+ {
+ factory = q->second;
+ }
+
+ //
+ // Get the type information.
+ //
+ ClassInfoPtr cls = getClassInfoById(id TSRMLS_CC);
+ if(!cls)
+ {
+ return 0;
+ }
+
+ if(factory)
+ {
+ zval* arg;
+ MAKE_STD_ZVAL(arg);
+ ZVAL_STRINGL(arg, STRCAST(id.c_str()), id.length(), 1);
+
+ zval* obj = 0;
+
+ zend_try
+ {
+ zend_call_method_with_1_params(&factory, 0, 0, "create", &obj, arg);
+ }
+ zend_catch
+ {
+ obj = 0;
+ }
+ zend_end_try();
+
+ zval_ptr_dtor(&arg);
+
+ //
+ // Bail out if an exception has already been thrown.
+ //
+ if(!obj || EG(exception))
+ {
+ throw AbortMarshaling();
+ }
+
+ AutoDestroy destroy(obj);
+
+ if(Z_TYPE_P(obj) == IS_NULL)
+ {
+ return 0;
+ }
+
+ return new ObjectReader(obj, cls, info TSRMLS_CC);
+ }
+
+ //
+ // If the requested type is an abstract class, then we give up.
+ //
+ if(cls->isAbstract)
+ {
+ return 0;
+ }
+
+ //
+ // Instantiate the object.
+ //
+ zval* obj;
+ MAKE_STD_ZVAL(obj);
+ AutoDestroy destroy(obj);
+
+ if(object_init_ex(obj, 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::ObjectFactoryI::destroy()
+{
+ _communicator = 0;
+}
+
+void
+IcePHP::ReaperTask::runTimerTask()
+{
+ IceUtil::StaticMutex::Lock sync(_registeredCommunicatorsMutex);
+
+ IceUtil::Time now = IceUtil::Time::now();
+ RegisteredCommunicatorMap::iterator p = _registeredCommunicators.begin();
+ while(p != _registeredCommunicators.end())
+ {
+ if(p->second->lastAccess + IceUtil::Time::seconds(p->second->expires * 60) <= now)
+ {
+ try
+ {
+ p->second->communicator->destroy();
+ }
+ catch(...)
+ {
+ }
+ _registeredCommunicators.erase(p++);
+ }
+ else
+ {
+ ++p;
+ }
+ }
}