1 // -*- Mode: C++; -*-
2 //                          Package   : omniNames
3 // NamingContext_i.cc       Author    : Tristan Richardson (tjr)
4 //
5 //    Copyright (C) 2002-2013 Apasphere Ltd
6 //    Copyright (C) 1997-1999 AT&T Laboratories Cambridge
7 //
8 //  This file is part of omniNames.
9 //
10 //  omniNames is free software; you can redistribute it and/or modify
11 //  it under the terms of the GNU General Public License as published by
12 //  the Free Software Foundation; either version 2 of the License, or
13 //  (at your option) any later version.
14 //
15 //  This program is distributed in the hope that it will be useful,
16 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 //  GNU General Public License for more details.
19 //
20 //  You should have received a copy of the GNU General Public License
21 //  along with this program.  If not, see http://www.gnu.org/licenses/
22 //
23 
24 #include <string.h>
25 
26 #include <assert.h>
27 #include <NamingContext_i.h>
28 #include <ObjectBinding.h>
29 #include <BindingIterator_i.h>
30 #include <omniORB4/omniURI.h>
31 
32 #ifdef HAVE_STD
33 #  include <iostream>
34    using namespace std;
35 #else
36 #  include <iostream.h>
37 #endif
38 
39 ReadersWritersLock NamingContext_i::lock;
40 NamingContext_i* NamingContext_i::headContext = (NamingContext_i*)0;
41 NamingContext_i* NamingContext_i::tailContext = (NamingContext_i*)0;
42 
OMNI_USING_NAMESPACE(omni)43 OMNI_USING_NAMESPACE(omni)
44 
45 //
46 // Ctor.
47 //
48 NamingContext_i::NamingContext_i(PortableServer::POA_ptr poa,
49 				 const PortableServer::ObjectId& id,
50 				 omniNameslog* l)
51   : redolog(l), nc_poa(poa)
52 {
53   headBinding = tailBinding = (ObjectBinding*)0;
54   size = 0;
55 
56   WriterLock w(lock);
57 
58   redolog->create(id);
59 
60   prev = tailContext;
61   next = (NamingContext_i*)0;
62   tailContext = this;
63   if (prev) {
64     prev->next = this;
65   }
66   else {
67     headContext = this;
68   }
69 
70   poa->activate_object_with_id(id, this);
71 }
72 
73 
74 //
75 // new_context().
76 //
77 
78 CosNaming::NamingContext_ptr
new_context()79 NamingContext_i::new_context()
80 {
81   LOG(4, "new_context");
82 
83   CORBA::Object_var ref = names_poa->create_reference(
84 				    CosNaming::NamingContext::_PD_repoId);
85   PortableServer::ObjectId_var id = names_poa->reference_to_id(ref);
86 
87   NamingContext_i* nc = new NamingContext_i(names_poa, id, redolog);
88   CosNaming::NamingContext_ptr ncref = nc->_this();
89   nc->_remove_ref();
90 
91   return ncref;
92 }
93 
94 
95 
96 //
97 // resolve_simple() returns the ObjectBinding for a given simple name.
98 // The thread calling this must have called either lock.readerIn() or
99 // lock.writerIn() before calling this routine.
100 //
101 
102 ObjectBinding*
resolve_simple(const CosNaming::Name & n)103 NamingContext_i::resolve_simple(const CosNaming::Name& n)
104 {
105   assert(n.length() == 1);
106 
107   LOG(4, "resolve_simple (" << n[0].id << '.' << n[0].kind << ")");
108 
109   for (ObjectBinding* ob = headBinding; ob; ob = ob->next) {
110 
111     assert(ob->binding.binding_name.length() == 1);
112 
113     if ((strcmp(n[0].id,ob->binding.binding_name[0].id) == 0) &&
114 	(strcmp(n[0].kind,ob->binding.binding_name[0].kind) == 0))
115       {
116 	LOG(4, "resolve_simple: found (" << n[0].id << '.' << n[0].kind << ")");
117 
118 	return ob;
119       }
120   }
121 
122   LOG(4, "resolve_simple: didn't find (" << n[0].id << '.' << n[0].kind << ")");
123 
124   throw CosNaming::NamingContext::NotFound(CosNaming::NamingContext::
125 					   missing_node, n);
126 #ifdef NEED_DUMMY_RETURN
127   return 0;
128 #endif
129 }
130 
131 
132 //
133 // resolve_compound() returns an object reference for the first component of
134 // the given name (which must be a context), and the rest of the name.
135 //
136 
137 CosNaming::NamingContext_ptr
resolve_compound(const CosNaming::Name & n,CosNaming::Name & restOfName)138 NamingContext_i::resolve_compound(const CosNaming::Name& n,
139 				  CosNaming::Name& restOfName)
140 {
141   if (omniORB::trace(4)) {
142     omniORB::logger log("omniNames: ");
143     log << "resolve_compound name (";
144 
145     for (unsigned int j = 0; j < n.length(); j++) {
146       if (j != 0) log << '/';
147       log << n[j].id << '.' << n[j].kind;
148     }
149     log << ")\n";
150   }
151 
152   if (n.length() == 0) {
153     throw CosNaming::NamingContext::InvalidName();
154   }
155 
156   CosNaming::Name contextName = n;
157   contextName.length(1);
158   restOfName.length(n.length() - 1);
159   for (unsigned int i = 0; i < n.length() - 1; i++) {
160     restOfName[i] = n[i + 1];
161   }
162 
163   ObjectBinding* ob;
164 
165   ReaderLock r(lock);
166 
167   try {
168     ob = resolve_simple(contextName);
169   }
170   catch (CosNaming::NamingContext::NotFound& ex) {
171     ex.rest_of_name = n;
172     throw;
173   }
174 
175   CosNaming::NamingContext_var context
176     = CosNaming::NamingContext::_narrow(ob->object);
177 
178   if (CORBA::is_nil((CosNaming::NamingContext_ptr)context) ||
179       (ob->binding.binding_type != CosNaming::ncontext))
180   {
181     LOG(4, "resolve_compound: object (" << n[0].id << '.' << n[0].kind <<
182         ") not bound as a context; raising exception");
183     throw CosNaming::NamingContext::NotFound(CosNaming::NamingContext::
184 					     not_context, n);
185   }
186   return CosNaming::NamingContext::_duplicate(context);
187 }
188 
189 
190 //
191 // resolve.
192 //
193 
194 CORBA::Object_ptr
resolve(const CosNaming::Name & n)195 NamingContext_i::resolve(const CosNaming::Name& n)
196 {
197   if (omniORB::trace(3)) {
198     omniORB::logger log("omniNames: ");
199     log << "resolve (";
200 
201     for (unsigned int j = 0; j < n.length(); j++) {
202       if (j != 0) log << '/';
203       log << n[j].id << '.' << n[j].kind;
204     }
205     log << ")\n";
206   }
207 
208   if (n.length() == 1) {
209     ReaderLock r(lock);
210     ObjectBinding* ob = resolve_simple(n);
211     return CORBA::Object::_duplicate(ob->object);
212   }
213   else {
214     CosNaming::Name restOfName;
215     CosNaming::NamingContext_var context = resolve_compound(n, restOfName);
216     return context->resolve(restOfName);
217   }
218 }
219 
220 
221 //
222 // bind_helper implements the 4 flavours of bind ([re]bind[_context]).
223 //
224 
225 void
bind_helper(const CosNaming::Name & n,CORBA::Object_ptr obj,CosNaming::BindingType t,CORBA::Boolean rebind)226 NamingContext_i::bind_helper(const CosNaming::Name& n, CORBA::Object_ptr obj,
227 			     CosNaming::BindingType t, CORBA::Boolean rebind)
228 {
229   if (n.length() == 1) {
230     //
231     // Bind a simple name - i.e. bind object in this context.
232     //
233 
234     LOG(2, "bind simple name (" << n[0].id << '.' << n[0].kind << ')');
235 
236     WriterLock w(lock);
237 
238     ObjectBinding* ob = 0;
239 
240     try {
241       ob = resolve_simple(n);
242       if (!rebind)
243 	throw CosNaming::NamingContext::AlreadyBound();
244     }
245     catch (CosNaming::NamingContext::NotFound& ex) {
246       ob = 0;
247     }
248 
249     CosNaming::NamingContext_var nc = _this();
250     redolog->bind(nc, n, obj, t);
251 
252     if (ob) {
253       LOG(4, "rebind: unbinding simple name (" << n[0].id << '.' << n[0].kind
254           << ')');
255       delete ob;
256     }
257 
258     new ObjectBinding(n, t, obj, this);
259 
260     LOG(4, "bound simple name (" << n[0].id << '.' << n[0].kind << ')');
261   }
262   else {
263     //
264     // Bind a compound name <c1;c2;...;cn> - i.e. bind object to name
265     // <c2;...;cn> in the context <c1>.
266     //
267 
268     if (omniORB::trace(2)) {
269       omniORB::logger log("omniNames: ");
270       log << "bind compound name (";
271 
272       for (unsigned int j = 0; j < n.length(); j++) {
273         if (j != 0) log << '/';
274         log << n[j].id << '.' << n[j].kind;
275       }
276       log << ")\n";
277     }
278 
279     CosNaming::Name restOfName;
280     CosNaming::NamingContext_var context = resolve_compound(n, restOfName);
281 
282     if (t == CosNaming::nobject) {
283       if (rebind)
284 	context->rebind(restOfName, obj);
285       else
286 	context->bind(restOfName, obj);
287     }
288     else {
289       if (rebind)
290 	context->rebind_context(restOfName,
291 				CosNaming::NamingContext::_narrow(obj));
292       else
293 	context->bind_context(restOfName,
294 			      CosNaming::NamingContext::_narrow(obj));
295     }
296   }
297 }
298 
299 
300 //
301 // unbind()
302 //
303 
304 void
unbind(const CosNaming::Name & n)305 NamingContext_i::unbind(const CosNaming::Name& n)
306 {
307   if (n.length() == 1) {
308     //
309     // Unbind a simple name - i.e. remove it from this context.
310     //
311 
312     LOG(2, "unbind simple name (" << n[0].id << '.' << n[0].kind << ')');
313 
314     WriterLock w(lock);
315 
316     ObjectBinding* ob = resolve_simple(n);
317 
318     CosNaming::NamingContext_var nc = _this();
319     redolog->unbind(nc, n);
320 
321     delete ob;
322   }
323   else {
324     //
325     // Unbind a compound name <c1;c2;...;cn> - i.e. unbind the name
326     // <c2;...;cn> from the context <c1>.
327     //
328 
329     if (omniORB::trace(2)) {
330       omniORB::logger log("omniNames: ");
331       log << "unbind compound name (";
332 
333       for (unsigned int j = 0; j < n.length(); j++) {
334         if (j != 0) log << '/';
335         log << n[j].id << '.' << n[j].kind;
336       }
337       log << ")\n";
338     }
339     CosNaming::Name restOfName;
340     CosNaming::NamingContext_var context = resolve_compound(n, restOfName);
341 
342     context->unbind(restOfName);
343   }
344 }
345 
346 
347 //
348 // bind_new_context()
349 //
350 
351 CosNaming::NamingContext_ptr
bind_new_context(const CosNaming::Name & n)352 NamingContext_i::bind_new_context(const CosNaming::Name& n)
353 {
354   if (n.length() == 1) {
355     //
356     // Bind a new context with a simple name - i.e. create a new context and
357     // bind it in this context.
358     //
359 
360     LOG(2, "bind_new_context simple name (" <<
361         n[0].id << '.' << n[0].kind << ')');
362 
363     CosNaming::NamingContext_ptr nc = new_context();
364     try {
365       bind_context(n, nc);
366     }
367     catch (...) {
368       nc->destroy();
369       CORBA::release(nc);
370       throw;
371     }
372     return nc;
373   }
374   else {
375     //
376     // Bind a new context with a compound name <c1;c2;...;cn> - i.e.
377     // bind_new_context <c2;...;cn> in the context <c1>.
378     //
379 
380     if (omniORB::trace(2)) {
381       omniORB::logger log("omniNames: ");
382       log << "bind_new_context compound name (";
383 
384       for (unsigned int j = 0; j < n.length(); j++) {
385         if (j != 0) log << '/';
386         log << n[j].id << '.' << n[j].kind;
387       }
388       log << ")\n";
389     }
390     CosNaming::Name restOfName;
391     CosNaming::NamingContext_var context = resolve_compound(n, restOfName);
392 
393     return context->bind_new_context(restOfName);
394   }
395 }
396 
397 
398 //
399 // destroy()
400 //
401 
402 void
destroy()403 NamingContext_i::destroy()
404 {
405   LOG(4, "destroy");
406 
407   WriterLock w(lock);
408 
409   if (headBinding)
410     throw CosNaming::NamingContext::NotEmpty();
411 
412   CosNaming::NamingContext_var nc = _this();
413   redolog->destroy(nc);
414 
415   PortableServer::ObjectId_var id = nc_poa->servant_to_id(this);
416   nc_poa->deactivate_object(id);
417 }
418 
419 
420 //
421 // list()
422 //
423 
424 void
list(CORBA::ULong how_many,CosNaming::BindingList_out bl,CosNaming::BindingIterator_out bi)425 NamingContext_i::list(CORBA::ULong how_many, CosNaming::BindingList_out bl,
426 		      CosNaming::BindingIterator_out bi)
427 {
428   lock.readerIn();
429 
430   LOG(3, "list context: how_many = " << how_many << ", size = " << size);
431 
432   CosNaming::BindingList_var all = new CosNaming::BindingList(size);
433   all->length(size);
434 
435   unsigned int i;
436   ObjectBinding* ob;
437 
438   for (ob = headBinding, i = 0; ob; ob = ob->next, i++) {
439     assert(i < size);
440     all[i] = ob->binding;
441   }
442 
443   lock.readerOut();
444 
445   if (all->length() <= how_many) {
446     // don't need an iterator.  All results can go back as a
447     // result of this call
448     bi = CosNaming::BindingIterator::_nil();
449     bl = all._retn();
450     return;
451   }
452 
453   BindingIterator_i* bii = new BindingIterator_i(names_poa, all._retn());
454 
455   bi = bii->_this();
456   bii->_remove_ref();
457 
458   bi->next_n(how_many, bl);
459 }
460 
461 
462 //
463 // destructor
464 //
465 
~NamingContext_i()466 NamingContext_i::~NamingContext_i()
467 {
468   WriterLock w(lock);
469 
470   if (prev) {
471     prev->next = next;
472   }
473   else {
474     headContext = next;
475   }
476   if (next) {
477     next->prev = prev;
478   }
479   else {
480     tailContext = prev;
481   }
482 
483   while (headBinding)
484     delete headBinding;
485 }
486 
487 
488 //
489 // CosNaming::NamingContextExt operations
490 //
491 
492 char*
to_string(const CosNaming::Name & name)493 NamingContext_i::to_string(const CosNaming::Name& name)
494 {
495   return omniURI::nameToString(name);
496 }
497 
498 CosNaming::Name*
to_name(const char * sn)499 NamingContext_i::to_name(const char* sn)
500 {
501   return omniURI::stringToName(sn);
502 }
503 
504 char*
to_url(const char * addr,const char * sn)505 NamingContext_i::to_url(const char* addr, const char* sn)
506 {
507   return omniURI::addrAndNameToURI(addr, sn);
508 }
509 
510 CORBA::Object_ptr
resolve_str(const char * sn)511 NamingContext_i::resolve_str(const char* sn)
512 {
513   CosNaming::Name_var name = omniURI::stringToName(sn);
514   return resolve(name);
515 }
516