summaryrefslogtreecommitdiff
path: root/ruby/src/IceRuby/ValueFactoryManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ruby/src/IceRuby/ValueFactoryManager.cpp')
-rw-r--r--ruby/src/IceRuby/ValueFactoryManager.cpp432
1 files changed, 432 insertions, 0 deletions
diff --git a/ruby/src/IceRuby/ValueFactoryManager.cpp b/ruby/src/IceRuby/ValueFactoryManager.cpp
new file mode 100644
index 00000000000..ee235bb9272
--- /dev/null
+++ b/ruby/src/IceRuby/ValueFactoryManager.cpp
@@ -0,0 +1,432 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 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.
+//
+// **********************************************************************
+
+#include <ValueFactoryManager.h>
+#include <Types.h>
+#include <Util.h>
+#include <Ice/LocalException.h>
+
+using namespace std;
+using namespace IceRuby;
+
+static VALUE _valueFactoryManagerClass;
+
+namespace
+{
+
+ClassInfoPtr
+getClassInfo(const string& id)
+{
+ ClassInfoPtr info;
+
+ 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.
+ //
+ info = lookupClassInfo("::Ice::UnknownSlicedObject");
+ }
+ else
+ {
+ info = lookupClassInfo(id);
+ }
+
+ return info;
+}
+
+}
+
+extern "C"
+void
+IceRuby_ValueFactoryManager_mark(ValueFactoryManagerPtr* p)
+{
+ assert(p);
+ (*p)->mark();
+}
+
+extern "C"
+void
+IceRuby_ValueFactoryManager_free(ValueFactoryManagerPtr* p)
+{
+ assert(p);
+ delete p;
+}
+
+IceRuby::ValueFactoryManager::ValueFactoryManager()
+{
+ //
+ // Create a Ruby wrapper around this object. Note that this is a cyclic reference.
+ //
+ _self = Data_Wrap_Struct(_valueFactoryManagerClass, IceRuby_ValueFactoryManager_mark,
+ IceRuby_ValueFactoryManager_free, new ValueFactoryManagerPtr(this));
+
+ _defaultFactory = new DefaultValueFactory;
+}
+
+IceRuby::ValueFactoryManager::~ValueFactoryManager()
+{
+ assert(_factories.empty());
+}
+
+void
+IceRuby::ValueFactoryManager::add(const Ice::ValueFactoryPtr& f, const string& id)
+{
+ Lock lock(*this);
+
+ if(id.empty())
+ {
+ if(_defaultFactory->getDelegate())
+ {
+ throw Ice::AlreadyRegisteredException(__FILE__, __LINE__, "value factory", id);
+ }
+
+ _defaultFactory->setDelegate(f);
+ }
+ else
+ {
+ FactoryMap::iterator p = _factories.find(id);
+ if(p != _factories.end())
+ {
+ throw Ice::AlreadyRegisteredException(__FILE__, __LINE__, "value factory", id);
+ }
+
+ _factories.insert(FactoryMap::value_type(id, f));
+ }
+}
+
+Ice::ValueFactoryPtr
+IceRuby::ValueFactoryManager::find(const string& id) const
+{
+ Lock lock(*this);
+
+ if(id.empty())
+ {
+ return _defaultFactory;
+ }
+
+ FactoryMap::const_iterator p = _factories.find(id);
+ if(p != _factories.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+void
+IceRuby::ValueFactoryManager::addValueFactory(VALUE f, const string& id)
+{
+ ICE_RUBY_TRY
+ {
+ add(new FactoryWrapper(f, false), id);
+ }
+ ICE_RUBY_CATCH
+}
+
+VALUE
+IceRuby::ValueFactoryManager::findValueFactory(const string& id) const
+{
+ Ice::ValueFactoryPtr f = find(id);
+ if(f)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(f);
+ if(w)
+ {
+ return w->getObject();
+ }
+ }
+
+ return Qnil;
+}
+
+void
+IceRuby::ValueFactoryManager::addObjectFactory(VALUE f, const string& id)
+{
+ ICE_RUBY_TRY
+ {
+ add(new FactoryWrapper(f, true), id);
+ }
+ ICE_RUBY_CATCH
+}
+
+VALUE
+IceRuby::ValueFactoryManager::findObjectFactory(const string& id) const
+{
+ Ice::ValueFactoryPtr f = find(id);
+ if(f)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(f);
+ if(w && w->isObjectFactory())
+ {
+ return w->getObject();
+ }
+ }
+
+ return Qnil;
+}
+
+void
+IceRuby::ValueFactoryManager::mark()
+{
+ Lock lock(*this);
+
+ for(FactoryMap::iterator p = _factories.begin(); p != _factories.end(); ++p)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(p->second);
+ if(w)
+ {
+ w->mark();
+ }
+ }
+
+ _defaultFactory->mark();
+}
+
+void
+IceRuby::ValueFactoryManager::markSelf()
+{
+ Lock lock(*this);
+
+ if(!NIL_P(_self))
+ {
+ rb_gc_mark(_self);
+ }
+}
+
+VALUE
+IceRuby::ValueFactoryManager::getObject() const
+{
+ return _self;
+}
+
+void
+IceRuby::ValueFactoryManager::destroy()
+{
+ FactoryMap factories;
+
+ {
+ Lock lock(*this);
+
+ factories.swap(_factories);
+
+ _self = Qnil;
+ }
+
+ for(FactoryMap::iterator p = factories.begin(); p != factories.end(); ++p)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(p->second);
+ if(w)
+ {
+ w->destroy();
+ }
+ }
+
+ _defaultFactory->destroy();
+}
+
+IceRuby::FactoryWrapper::FactoryWrapper(VALUE factory, bool isObjectFactory) :
+ _factory(factory),
+ _isObjectFactory(isObjectFactory)
+{
+}
+
+Ice::ValuePtr
+IceRuby::FactoryWrapper::create(const string& id)
+{
+ //
+ // Get the type information.
+ //
+ ClassInfoPtr info = getClassInfo(id);
+
+ if(!info)
+ {
+ return 0;
+ }
+
+ //
+ // Invoke the create method on the Ruby factory object.
+ //
+ volatile VALUE str = createString(id);
+ volatile VALUE obj = callRuby(rb_funcall, _factory, rb_intern("create"), 1, str);
+ if(NIL_P(obj))
+ {
+ return 0;
+ }
+
+ return new ObjectReader(obj, info);
+}
+
+VALUE
+IceRuby::FactoryWrapper::getObject() const
+{
+ return _factory;
+}
+
+bool
+IceRuby::FactoryWrapper::isObjectFactory() const
+{
+ return _isObjectFactory;
+}
+
+void
+IceRuby::FactoryWrapper::mark()
+{
+ rb_gc_mark(_factory);
+}
+
+void
+IceRuby::FactoryWrapper::destroy()
+{
+ if(_isObjectFactory)
+ {
+ callRuby(rb_funcall, _factory, rb_intern("destroy"), 0);
+ }
+}
+
+Ice::ValuePtr
+IceRuby::DefaultValueFactory::create(const string& id)
+{
+ Ice::ValuePtr v;
+
+ //
+ // Give the application-provided default factory a chance to create the object first.
+ //
+ if(_delegate)
+ {
+ v = _delegate->create(id);
+ if(v)
+ {
+ return v;
+ }
+ }
+
+ //
+ // Get the type information.
+ //
+ ClassInfoPtr info = getClassInfo(id);
+
+ if(!info)
+ {
+ return 0;
+ }
+
+ //
+ // NOTE: We don't do this in Ruby because a generated class can be re-opened to define operations.
+ //
+ ////
+ //// If the requested type is an abstract class, then we give up.
+ ////
+ //if(info->isAbstract)
+ //{
+ // return 0;
+ //}
+
+ //
+ // Instantiate the object.
+ //
+ volatile VALUE obj = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), info->rubyClass);
+ assert(!NIL_P(obj));
+ return new ObjectReader(obj, info);
+}
+
+void
+IceRuby::DefaultValueFactory::setDelegate(const Ice::ValueFactoryPtr& d)
+{
+ _delegate = d;
+}
+
+VALUE
+IceRuby::DefaultValueFactory::getObject() const
+{
+ if(_delegate)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
+ if(w)
+ {
+ return w->getObject();
+ }
+ }
+
+ return Qnil;
+}
+
+void
+IceRuby::DefaultValueFactory::mark()
+{
+ if(_delegate)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
+ if(w)
+ {
+ w->mark();
+ }
+ }
+}
+
+void
+IceRuby::DefaultValueFactory::destroy()
+{
+ if(_delegate)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
+ if(w)
+ {
+ w->destroy();
+ }
+ }
+
+ _delegate = 0;
+}
+
+extern "C"
+VALUE
+IceRuby_ValueFactoryManager_add(VALUE self, VALUE factory, VALUE id)
+{
+ ICE_RUBY_TRY
+ {
+ ValueFactoryManagerPtr* p = reinterpret_cast<ValueFactoryManagerPtr*>(DATA_PTR(self));
+ assert(p);
+
+ string type = getString(id);
+ (*p)->addValueFactory(factory, type);
+ }
+ ICE_RUBY_CATCH
+ return Qnil;
+}
+
+extern "C"
+VALUE
+IceRuby_ValueFactoryManager_find(VALUE self, VALUE id)
+{
+ ICE_RUBY_TRY
+ {
+ ValueFactoryManagerPtr* p = reinterpret_cast<ValueFactoryManagerPtr*>(DATA_PTR(self));
+ assert(p);
+
+ string type = getString(id);
+ return (*p)->findValueFactory(type);
+ }
+ ICE_RUBY_CATCH
+ return Qnil;
+}
+
+bool
+IceRuby::initValueFactoryManager(VALUE iceModule)
+{
+ _valueFactoryManagerClass = rb_define_class_under(iceModule, "ValueFactoryManagerI", rb_cObject);
+
+ //
+ // Instance methods.
+ //
+ rb_define_method(_valueFactoryManagerClass, "add", CAST_METHOD(IceRuby_ValueFactoryManager_add), 2);
+ rb_define_method(_valueFactoryManagerClass, "find", CAST_METHOD(IceRuby_ValueFactoryManager_find), 1);
+
+ return true;
+}