1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <ValueFactoryManager.h>
6 #include <Types.h>
7 #include <Util.h>
8 #include <Ice/LocalException.h>
9 
10 using namespace std;
11 using namespace IceRuby;
12 
13 static VALUE _valueFactoryManagerClass;
14 
15 namespace
16 {
17 
18 ClassInfoPtr
getClassInfo(const string & id)19 getClassInfo(const string& id)
20 {
21     ClassInfoPtr info;
22 
23     if(id == Ice::Object::ice_staticId())
24     {
25         //
26         // When the ID is that of Ice::Object, it indicates that the stream has not
27         // found a factory and is providing us an opportunity to preserve the object.
28         //
29         info = lookupClassInfo("::Ice::UnknownSlicedValue");
30     }
31     else
32     {
33         info = lookupClassInfo(id);
34     }
35 
36     return info;
37 }
38 
39 }
40 
41 extern "C"
42 void
IceRuby_ValueFactoryManager_mark(ValueFactoryManagerPtr * p)43 IceRuby_ValueFactoryManager_mark(ValueFactoryManagerPtr* p)
44 {
45     assert(p);
46     (*p)->mark();
47 }
48 
49 extern "C"
50 void
IceRuby_ValueFactoryManager_free(ValueFactoryManagerPtr * p)51 IceRuby_ValueFactoryManager_free(ValueFactoryManagerPtr* p)
52 {
53     assert(p);
54     delete p;
55 }
56 
ValueFactoryManager()57 IceRuby::ValueFactoryManager::ValueFactoryManager()
58 {
59     //
60     // Create a Ruby wrapper around this object. Note that this is a cyclic reference.
61     //
62     _self = Data_Wrap_Struct(_valueFactoryManagerClass, IceRuby_ValueFactoryManager_mark,
63                              IceRuby_ValueFactoryManager_free, new ValueFactoryManagerPtr(this));
64 
65     _defaultFactory = new DefaultValueFactory;
66 }
67 
~ValueFactoryManager()68 IceRuby::ValueFactoryManager::~ValueFactoryManager()
69 {
70     assert(_factories.empty());
71 }
72 
73 void
add(const Ice::ValueFactoryPtr & f,const string & id)74 IceRuby::ValueFactoryManager::add(const Ice::ValueFactoryPtr& f, const string& id)
75 {
76     Lock lock(*this);
77 
78     if(id.empty())
79     {
80         if(_defaultFactory->getDelegate())
81         {
82             throw Ice::AlreadyRegisteredException(__FILE__, __LINE__, "value factory", id);
83         }
84 
85         _defaultFactory->setDelegate(f);
86     }
87     else
88     {
89         FactoryMap::iterator p = _factories.find(id);
90         if(p != _factories.end())
91         {
92             throw Ice::AlreadyRegisteredException(__FILE__, __LINE__, "value factory", id);
93         }
94 
95         _factories.insert(FactoryMap::value_type(id, f));
96     }
97 }
98 
99 Ice::ValueFactoryPtr
find(const string & id) const100 IceRuby::ValueFactoryManager::find(const string& id) const ICE_NOEXCEPT
101 {
102     Lock lock(*this);
103 
104     if(id.empty())
105     {
106         return _defaultFactory;
107     }
108 
109     FactoryMap::const_iterator p = _factories.find(id);
110     if(p != _factories.end())
111     {
112         return p->second;
113     }
114 
115     return 0;
116 }
117 
118 void
addValueFactory(VALUE f,const string & id)119 IceRuby::ValueFactoryManager::addValueFactory(VALUE f, const string& id)
120 {
121     ICE_RUBY_TRY
122     {
123         add(new FactoryWrapper(f, false), id);
124     }
125     ICE_RUBY_CATCH
126 }
127 
128 VALUE
findValueFactory(const string & id) const129 IceRuby::ValueFactoryManager::findValueFactory(const string& id) const
130 {
131     Ice::ValueFactoryPtr f = find(id);
132     if(f)
133     {
134         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(f);
135         if(w)
136         {
137             return w->getObject();
138         }
139     }
140 
141     return Qnil;
142 }
143 
144 void
addObjectFactory(VALUE f,const string & id)145 IceRuby::ValueFactoryManager::addObjectFactory(VALUE f, const string& id)
146 {
147     ICE_RUBY_TRY
148     {
149         add(new FactoryWrapper(f, true), id);
150     }
151     ICE_RUBY_CATCH
152 }
153 
154 VALUE
findObjectFactory(const string & id) const155 IceRuby::ValueFactoryManager::findObjectFactory(const string& id) const
156 {
157     Ice::ValueFactoryPtr f = find(id);
158     if(f)
159     {
160         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(f);
161         if(w && w->isObjectFactory())
162         {
163             return w->getObject();
164         }
165     }
166 
167     return Qnil;
168 }
169 
170 void
mark()171 IceRuby::ValueFactoryManager::mark()
172 {
173     Lock lock(*this);
174 
175     for(FactoryMap::iterator p = _factories.begin(); p != _factories.end(); ++p)
176     {
177         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(p->second);
178         if(w)
179         {
180             w->mark();
181         }
182     }
183 
184     _defaultFactory->mark();
185 }
186 
187 void
markSelf()188 IceRuby::ValueFactoryManager::markSelf()
189 {
190     volatile VALUE self;
191 
192     {
193         Lock lock(*this);
194 
195         self = _self;
196     }
197 
198     if(!NIL_P(self))
199     {
200         rb_gc_mark(self);
201     }
202 }
203 
204 VALUE
getObject() const205 IceRuby::ValueFactoryManager::getObject() const
206 {
207     return _self;
208 }
209 
210 void
destroy()211 IceRuby::ValueFactoryManager::destroy()
212 {
213     FactoryMap factories;
214 
215     {
216         Lock lock(*this);
217         if(_self == Qnil)
218         {
219             //
220             // Nothing to do if already destroyed (this can occur if communicator destroy is called multiple times)
221             //
222             return;
223         }
224 
225         factories.swap(_factories);
226 
227         _self = Qnil;
228     }
229 
230     for(FactoryMap::iterator p = factories.begin(); p != factories.end(); ++p)
231     {
232         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(p->second);
233         if(w)
234         {
235             w->destroy();
236         }
237     }
238 
239     _defaultFactory->destroy();
240 }
241 
FactoryWrapper(VALUE factory,bool isObjectFactory)242 IceRuby::FactoryWrapper::FactoryWrapper(VALUE factory, bool isObjectFactory) :
243     _factory(factory),
244     _isObjectFactory(isObjectFactory)
245 {
246 }
247 
248 Ice::ValuePtr
create(const string & id)249 IceRuby::FactoryWrapper::create(const string& id)
250 {
251     //
252     // Get the type information.
253     //
254     ClassInfoPtr info = getClassInfo(id);
255 
256     if(!info)
257     {
258         return 0;
259     }
260 
261     //
262     // Invoke the create method on the Ruby factory object.
263     //
264     volatile VALUE str = createString(id);
265     volatile VALUE obj = callRuby(rb_funcall, _factory, rb_intern("create"), 1, str);
266     if(NIL_P(obj))
267     {
268         return 0;
269     }
270 
271     return new ObjectReader(obj, info);
272 }
273 
274 VALUE
getObject() const275 IceRuby::FactoryWrapper::getObject() const
276 {
277     return _factory;
278 }
279 
280 bool
isObjectFactory() const281 IceRuby::FactoryWrapper::isObjectFactory() const
282 {
283     return _isObjectFactory;
284 }
285 
286 void
mark()287 IceRuby::FactoryWrapper::mark()
288 {
289     rb_gc_mark(_factory);
290 }
291 
292 void
destroy()293 IceRuby::FactoryWrapper::destroy()
294 {
295     if(_isObjectFactory)
296     {
297         callRuby(rb_funcall, _factory, rb_intern("destroy"), 0);
298     }
299 }
300 
301 Ice::ValuePtr
create(const string & id)302 IceRuby::DefaultValueFactory::create(const string& id)
303 {
304     Ice::ValuePtr v;
305 
306     //
307     // Give the application-provided default factory a chance to create the object first.
308     //
309     if(_delegate)
310     {
311         v = _delegate->create(id);
312         if(v)
313         {
314             return v;
315         }
316     }
317 
318     //
319     // Get the type information.
320     //
321     ClassInfoPtr info = getClassInfo(id);
322 
323     if(!info)
324     {
325         return 0;
326     }
327 
328     //
329     // NOTE: We don't do this in Ruby because a generated class can be re-opened to define operations.
330     //
331     ////
332     //// If the requested type is an abstract class, then we give up.
333     ////
334     //if(info->isAbstract)
335     //{
336     //    return 0;
337     //}
338 
339     //
340     // Instantiate the object.
341     //
342     volatile VALUE obj = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), info->rubyClass);
343     assert(!NIL_P(obj));
344     return new ObjectReader(obj, info);
345 }
346 
347 void
setDelegate(const Ice::ValueFactoryPtr & d)348 IceRuby::DefaultValueFactory::setDelegate(const Ice::ValueFactoryPtr& d)
349 {
350     _delegate = d;
351 }
352 
353 VALUE
getObject() const354 IceRuby::DefaultValueFactory::getObject() const
355 {
356     if(_delegate)
357     {
358         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
359         if(w)
360         {
361             return w->getObject();
362         }
363     }
364 
365     return Qnil;
366 }
367 
368 void
mark()369 IceRuby::DefaultValueFactory::mark()
370 {
371     if(_delegate)
372     {
373         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
374         if(w)
375         {
376             w->mark();
377         }
378     }
379 }
380 
381 void
destroy()382 IceRuby::DefaultValueFactory::destroy()
383 {
384     if(_delegate)
385     {
386         FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
387         if(w)
388         {
389             w->destroy();
390         }
391     }
392 
393     _delegate = 0;
394 }
395 
396 extern "C"
397 VALUE
IceRuby_ValueFactoryManager_add(VALUE self,VALUE factory,VALUE id)398 IceRuby_ValueFactoryManager_add(VALUE self, VALUE factory, VALUE id)
399 {
400     ICE_RUBY_TRY
401     {
402         ValueFactoryManagerPtr* p = reinterpret_cast<ValueFactoryManagerPtr*>(DATA_PTR(self));
403         assert(p);
404 
405         string type = getString(id);
406         (*p)->addValueFactory(factory, type);
407     }
408     ICE_RUBY_CATCH
409     return Qnil;
410 }
411 
412 extern "C"
413 VALUE
IceRuby_ValueFactoryManager_find(VALUE self,VALUE id)414 IceRuby_ValueFactoryManager_find(VALUE self, VALUE id)
415 {
416     ICE_RUBY_TRY
417     {
418         ValueFactoryManagerPtr* p = reinterpret_cast<ValueFactoryManagerPtr*>(DATA_PTR(self));
419         assert(p);
420 
421         string type = getString(id);
422         return (*p)->findValueFactory(type);
423     }
424     ICE_RUBY_CATCH
425     return Qnil;
426 }
427 
428 bool
initValueFactoryManager(VALUE iceModule)429 IceRuby::initValueFactoryManager(VALUE iceModule)
430 {
431     _valueFactoryManagerClass = rb_define_class_under(iceModule, "ValueFactoryManagerI", rb_cObject);
432 
433     //
434     // Instance methods.
435     //
436     rb_define_method(_valueFactoryManagerClass, "add", CAST_METHOD(IceRuby_ValueFactoryManager_add), 2);
437     rb_define_method(_valueFactoryManagerClass, "find", CAST_METHOD(IceRuby_ValueFactoryManager_find), 1);
438 
439     return true;
440 }
441