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