/jboss-as-7.1.1.Final/jacorb/src/main/java/org/jboss/as/jacorb/naming/CorbaNamingContext.java
Java | 662 lines | 410 code | 101 blank | 151 comment | 144 complexity | 650ff63f5008292c4b19f7e2501c5b74 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
1/*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2011, Red Hat, Inc., and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22
23package org.jboss.as.jacorb.naming;
24
25import java.io.IOException;
26import java.io.ObjectInputStream;
27import java.io.Serializable;
28import java.util.Hashtable;
29import java.util.Iterator;
30import java.util.Map;
31
32import org.jacorb.naming.BindingIteratorImpl;
33import org.jacorb.naming.Name;
34import org.jboss.as.jacorb.JacORBLogger;
35import org.omg.CORBA.INTERNAL;
36import org.omg.CORBA.ORB;
37import org.omg.CosNaming.Binding;
38import org.omg.CosNaming.BindingIteratorHelper;
39import org.omg.CosNaming.BindingIteratorHolder;
40import org.omg.CosNaming.BindingListHolder;
41import org.omg.CosNaming.BindingType;
42import org.omg.CosNaming.NameComponent;
43import org.omg.CosNaming.NamingContext;
44import org.omg.CosNaming.NamingContextExtHelper;
45import org.omg.CosNaming.NamingContextExtPOA;
46import org.omg.CosNaming.NamingContextExtPackage.InvalidAddress;
47import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
48import org.omg.CosNaming.NamingContextPackage.CannotProceed;
49import org.omg.CosNaming.NamingContextPackage.InvalidName;
50import org.omg.CosNaming.NamingContextPackage.NotEmpty;
51import org.omg.CosNaming.NamingContextPackage.NotFound;
52import org.omg.CosNaming.NamingContextPackage.NotFoundReason;
53import org.omg.PortableServer.POA;
54
55/**
56 * <p>
57 * This class implements an in-VM CORBA Naming Server that caches for JBoss to use. All contexts keep a cache of the
58 * local sub-contexts to avoid unnecessary remote calls when resolving a complex name.
59 * </p>
60 *
61 * @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
62 */
63public class CorbaNamingContext extends NamingContextExtPOA implements Serializable {
64
65 private static final long serialVersionUID = 132820915998903191L;
66
67 /**
68 * static references to the running ORB and root POA.
69 */
70 private static ORB orb;
71 private static POA rootPoa;
72
73 /**
74 * the naming service POA - i.e. the POA that activates all naming contexts.
75 */
76 private transient POA poa;
77
78 /**
79 * table of all name bindings in this contexts, ie. name -> obj ref.
80 */
81 private Map<Name, Object> names = new Hashtable<Name, Object>();
82
83 /**
84 * table of all subordinate naming contexts, ie. name -> obj ref.
85 */
86 private Map<Name, Object> contexts = new Hashtable<Name, Object>();
87
88 /**
89 * cache of all active naming context implementations - used when resolving contexts recursively to avoid
90 * unnecessary remote calls that may lead to thread pool depletion.
91 */
92 private static Map<String, CorbaNamingContext> contextImpls = new Hashtable<String, CorbaNamingContext>();
93
94 /**
95 * no tests of bound objects for existence
96 */
97 private boolean noPing = false;
98
99 /**
100 * purge?
101 */
102 private boolean doPurge = false;
103
104 private boolean destroyed = false;
105
106 private int childCount = 0;
107
108 //======================================= Initialization Methods ==================================//
109
110 /**
111 * <p>
112 * This method needs to be called once to initialize the static fields orb and rootPoa.
113 * </p>
114 *
115 * @param orb a reference to the running {@code ORB} instance.
116 * @param rootPoa a reference to the root {@code POA}.
117 */
118 public static void init(org.omg.CORBA.ORB orb, org.omg.PortableServer.POA rootPoa) {
119 CorbaNamingContext.orb = orb;
120 CorbaNamingContext.rootPoa = rootPoa;
121 }
122
123 /**
124 * <p>
125 * This method needs to be called for each newly created or re-read naming context to set its POA.
126 * </p>
127 *
128 * @param poa a reference to the Naming Service {@code POA}.
129 * @param doPurge a boolean that indicates if dead objects should be purged from the context ({@code true}) upon cleanup
130 * or not ({@code false}).
131 * @param noPing a boolean that indicates if the method {@code resolve} should check if the resolved name or context is
132 * alive before returning it. If {@code false}, the name will be checked (default)
133 */
134 public void init(POA poa, boolean doPurge, boolean noPing) {
135 this.poa = poa;
136 this.doPurge = doPurge;
137 this.noPing = noPing;
138 }
139
140 //======================================= NamingContextOperation Methods ==================================//
141
142 public void bind(NameComponent[] nc, org.omg.CORBA.Object obj) throws NotFound, CannotProceed, InvalidName,
143 AlreadyBound {
144 if (this.destroyed)
145 throw new CannotProceed();
146
147 if (nc == null || nc.length == 0)
148 throw new InvalidName();
149
150 if (obj == null)
151 throw new org.omg.CORBA.BAD_PARAM();
152
153 Name n = new Name(nc);
154 Name ctx = n.ctxName();
155 NameComponent nb = n.baseNameComponent();
156
157 if (ctx == null) {
158 if (this.names.containsKey(n)) {
159 // if the name is still in use, try to ping the object
160 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.names.get(n);
161 if (isDead(ref)) {
162 rebind(n.components(), obj);
163 return;
164 }
165 throw new AlreadyBound();
166 } else if (this.contexts.containsKey(n)) {
167 // if the name is still in use, try to ping the object
168 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.contexts.get(n);
169 if (isDead(ref))
170 unbind(n.components());
171 throw new AlreadyBound();
172 }
173
174 if ((this.names.put(n, obj)) != null)
175 throw new CannotProceed(_this(), n.components());
176
177 JacORBLogger.ROOT_LOGGER.debugBoundName(n.toString());
178 } else {
179 NameComponent[] ncx = new NameComponent[]{nb};
180 org.omg.CORBA.Object context = this.resolve(ctx.components());
181
182 // try first to call the context implementation object directly.
183 String contextOID = this.getObjectOID(context);
184 CorbaNamingContext jbossContext = (contextOID == null ? null : contextImpls.get(contextOID));
185 if (jbossContext != null)
186 jbossContext.bind(ncx, obj);
187 else
188 NamingContextExtHelper.narrow(context).bind(ncx, obj);
189 }
190 }
191
192 public void bind_context(NameComponent[] nc, NamingContext obj) throws NotFound, CannotProceed, InvalidName,
193 AlreadyBound {
194 if (this.destroyed)
195 throw new CannotProceed();
196
197 Name n = new Name(nc);
198 Name ctx = n.ctxName();
199 NameComponent nb = n.baseNameComponent();
200
201 if (ctx == null) {
202 if (this.names.containsKey(n)) {
203 // if the name is still in use, try to ping the object
204 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.names.get(n);
205 if (isDead(ref))
206 unbind(n.components());
207 else
208 throw new AlreadyBound();
209 } else if (this.contexts.containsKey(n)) {
210 // if the name is still in use, try to ping the object
211 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.contexts.get(n);
212 if (isDead(ref)) {
213 rebind_context(n.components(), obj);
214 return;
215 }
216 throw new AlreadyBound();
217 }
218
219 if ((this.contexts.put(n, obj)) != null)
220 throw new CannotProceed(_this(), n.components());
221
222 JacORBLogger.ROOT_LOGGER.debugBoundContext(n.toString());
223 } else {
224 NameComponent[] ncx = new NameComponent[]{nb};
225 org.omg.CORBA.Object context = this.resolve(ctx.components());
226
227 // try first to call the context implementation object directly.
228 String contextOID = this.getObjectOID(context);
229 CorbaNamingContext jbossContext = (contextOID == null ? null : contextImpls.get(contextOID));
230 if (jbossContext != null)
231 jbossContext.bind_context(ncx, obj);
232 else
233 NamingContextExtHelper.narrow(context).bind_context(ncx, obj);
234 }
235 }
236
237 public NamingContext bind_new_context(NameComponent[] nc) throws NotFound, CannotProceed, InvalidName, AlreadyBound {
238 if (this.destroyed)
239 throw new CannotProceed();
240
241 if (nc == null || nc.length == 0)
242 throw new InvalidName();
243
244 NamingContext context = new_context();
245 if (context == null)
246 throw new CannotProceed();
247
248 bind_context(nc, context);
249 return context;
250 }
251
252 public void destroy() throws NotEmpty {
253 if (this.destroyed)
254 return;
255
256 if (!this.names.isEmpty() || !this.contexts.isEmpty())
257 throw new NotEmpty();
258 else {
259 this.names = null;
260 this.contexts = null;
261 this.destroyed = true;
262 }
263 }
264
265 public void list(int how_many, BindingListHolder bl, BindingIteratorHolder bi) {
266 if (this.destroyed)
267 return;
268
269 Binding[] result;
270 this.cleanup();
271
272 int size = how_many();
273
274 Iterator<Name> names = this.names.keySet().iterator();
275 Iterator<Name> contexts = this.contexts.keySet().iterator();
276
277 if (how_many < size) {
278 // counter for copies
279 int how_many_ctr = how_many;
280
281 // set up an array with "how_many" bindings
282 result = new Binding[how_many];
283 for (; names.hasNext() && how_many_ctr > 0; how_many_ctr--)
284 result[how_many_ctr - 1] = new Binding((names.next()).components(), BindingType.nobject);
285
286 for (; contexts.hasNext() && how_many_ctr > 0; how_many_ctr--)
287 result[how_many_ctr - 1] = new Binding((contexts.next()).components(), BindingType.ncontext);
288
289 // create a new BindingIterator for the remaining arrays
290 size -= how_many;
291 Binding[] rest = new Binding[size];
292 for (; names.hasNext() && size > 0; size--)
293 rest[size - 1] = new Binding((names.next()).components(), BindingType.nobject);
294
295 for (; contexts.hasNext() && size > 0; size--)
296 rest[size - 1] = new Binding((contexts.next()).components(), BindingType.ncontext);
297
298 org.omg.CORBA.Object o;
299 try {
300 // Iterators are activated with the RootPOA (transient)
301 byte[] oid = rootPoa.activate_object(new BindingIteratorImpl(rest));
302 o = rootPoa.id_to_reference(oid);
303 } catch (Exception e) {
304 JacORBLogger.ROOT_LOGGER.logInternalError(e);
305 throw new INTERNAL(e.toString());
306 }
307
308 bi.value = BindingIteratorHelper.narrow(o);
309 } else {
310 result = new Binding[size];
311 for (; names.hasNext() && size > 0; size--)
312 result[size - 1] = new Binding((names.next()).components(), BindingType.nobject);
313
314 for (; contexts.hasNext() && size > 0; size--)
315 result[size - 1] = new Binding((contexts.next()).components(), BindingType.ncontext);
316 }
317
318 bl.value = result;
319 }
320
321 public NamingContext new_context() {
322 try {
323 // create and initialize a new context.
324 CorbaNamingContext newContextImpl = new CorbaNamingContext();
325 newContextImpl.init(this.poa, this.doPurge, this.noPing);
326 // create the oid for the new context and activate it with the naming service POA.
327 String oid = new String(this.poa.servant_to_id(this)) + "/ctx" + (++this.childCount);
328 this.poa.activate_object_with_id(oid.getBytes(), newContextImpl);
329 // add the newly-created context to the cache.
330 contextImpls.put(oid, newContextImpl);
331 return NamingContextExtHelper.narrow(this.poa.create_reference_with_id(oid.getBytes(),
332 "IDL:omg.org/CosNaming/NamingContextExt:1.0"));
333 } catch (Exception e) {
334 JacORBLogger.ROOT_LOGGER.failedToCreateNamingContext(e);
335 return null;
336 }
337 }
338
339 public void rebind(NameComponent[] nc, org.omg.CORBA.Object obj) throws NotFound, CannotProceed, InvalidName {
340 if (this.destroyed)
341 throw new CannotProceed();
342
343 if (nc == null || nc.length == 0)
344 throw new InvalidName();
345
346 if (obj == null)
347 throw new org.omg.CORBA.BAD_PARAM();
348
349 Name n = new Name(nc);
350 Name ctx = n.ctxName();
351 NameComponent nb = n.baseNameComponent();
352
353 if (ctx == null) {
354 // the name is bound, but it is bound to a context - the client should have been using rebind_context!
355 if (this.contexts.containsKey(n))
356 throw new NotFound(NotFoundReason.not_object, new NameComponent[]{nb});
357
358 // try remove an existing binding.
359 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.names.remove(n);
360 if (ref != null)
361 ref._release();
362
363 // do the rebinding in this context
364 this.names.put(n, obj);
365 JacORBLogger.ROOT_LOGGER.debugBoundName(n.toString());
366 } else {
367 // rebind in the correct context
368 NameComponent[] ncx = new NameComponent[]{nb};
369 org.omg.CORBA.Object context = this.resolve(ctx.components());
370
371 // try first to call the context implementation object directly.
372 String contextOID = this.getObjectOID(context);
373 CorbaNamingContext jbossContext = (contextOID == null ? null : contextImpls.get(contextOID));
374 if (jbossContext != null)
375 jbossContext.rebind(ncx, obj);
376 else
377 NamingContextExtHelper.narrow(context).rebind(ncx, obj);
378 }
379 }
380
381 public void rebind_context(NameComponent[] nc, NamingContext obj) throws NotFound, CannotProceed, InvalidName {
382 if (this.destroyed)
383 throw new CannotProceed();
384
385 if (nc == null || nc.length == 0)
386 throw new InvalidName();
387
388 if (obj == null)
389 throw new org.omg.CORBA.BAD_PARAM();
390
391 Name n = new Name(nc);
392 Name ctx = n.ctxName();
393 NameComponent nb = n.baseNameComponent();
394
395 if (ctx == null) {
396 // the name is bound, but it is bound to an object - the client should have been using rebind().
397 if (this.names.containsKey(n))
398 throw new NotFound(NotFoundReason.not_context, new NameComponent[]{nb});
399
400 // try to remove an existing context binding.
401 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.contexts.remove(n);
402 if (ref != null) {
403 ref._release();
404 // remove the old context from the implementation cache.
405 String oid = this.getObjectOID(ref);
406 if (oid != null)
407 contextImpls.remove(oid);
408 }
409
410 this.contexts.put(n, obj);
411 JacORBLogger.ROOT_LOGGER.debugBoundContext(n.baseNameComponent().id);
412 } else {
413 // rebind in the correct context
414 NameComponent[] ncx = new NameComponent[]{nb};
415 org.omg.CORBA.Object context = this.resolve(ctx.components());
416
417 // try first to call the context implementation object directly.
418 String contextOID = this.getObjectOID(context);
419 CorbaNamingContext jbossContext = (contextOID == null ? null : contextImpls.get(contextOID));
420 if (jbossContext != null)
421 jbossContext.rebind_context(ncx, obj);
422 else
423 NamingContextExtHelper.narrow(context).rebind_context(ncx, obj);
424 }
425 }
426
427 public org.omg.CORBA.Object resolve(NameComponent[] nc) throws NotFound, CannotProceed, InvalidName {
428 if (this.destroyed)
429 throw new CannotProceed();
430
431 if (nc == null || nc.length == 0)
432 throw new InvalidName();
433
434 Name n = new Name(nc[0]);
435 if (nc.length > 1) {
436 org.omg.CORBA.Object next_context = (org.omg.CORBA.Object) this.contexts.get(n);
437 if ((next_context == null) || (isDead(next_context)))
438 throw new NotFound(NotFoundReason.missing_node, nc);
439
440 NameComponent[] nc_prime = new NameComponent[nc.length - 1];
441 System.arraycopy(nc, 1, nc_prime, 0, nc_prime.length);
442
443 // try first to call the context implementation object directly.
444 String contextOID = this.getObjectOID(next_context);
445 CorbaNamingContext jbossContext = (contextOID == null ? null : contextImpls.get(contextOID));
446 if (jbossContext != null)
447 return jbossContext.resolve(nc_prime);
448 else
449 return NamingContextExtHelper.narrow(next_context).resolve(nc_prime);
450 } else {
451 org.omg.CORBA.Object result = (org.omg.CORBA.Object) this.contexts.get(n);
452
453 if (result == null)
454 result = (org.omg.CORBA.Object) this.names.get(n);
455
456 if (result == null)
457 throw new NotFound(NotFoundReason.missing_node, n.components());
458
459 if (!noPing && isDead(result))
460 throw new NotFound(NotFoundReason.missing_node, n.components());
461
462 return result;
463 }
464 }
465
466 public void unbind(NameComponent[] nc) throws NotFound, CannotProceed, InvalidName {
467 if (this.destroyed)
468 throw new CannotProceed();
469
470 if (nc == null || nc.length == 0)
471 throw new InvalidName();
472
473 Name n = new Name(nc);
474 Name ctx = n.ctxName();
475 NameComponent nb = n.baseNameComponent();
476
477 if (ctx == null) {
478 if (this.names.containsKey(n)) {
479 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.names.remove(n);
480 ref._release();
481 JacORBLogger.ROOT_LOGGER.debugUnboundObject(n.toString());
482 } else if (this.contexts.containsKey(n)) {
483 org.omg.CORBA.Object ref = (org.omg.CORBA.Object) this.contexts.remove(n);
484 ref._release();
485 // remove the context from the implementation cache.
486 String oid = this.getObjectOID(ref);
487 if (oid != null)
488 contextImpls.remove(oid);
489
490 JacORBLogger.ROOT_LOGGER.debugUnboundObject(n.toString());
491 } else {
492 JacORBLogger.ROOT_LOGGER.failedToUnbindObject(n.toString());
493 throw new NotFound(NotFoundReason.not_context, n.components());
494 }
495 } else {
496 NameComponent[] ncx = new NameComponent[]{nb};
497 org.omg.CORBA.Object context = this.resolve(ctx.components());
498
499 // try first to call the context implementation object directly.
500 String contextOID = this.getObjectOID(context);
501 CorbaNamingContext jbossContext = (contextOID == null ? null : contextImpls.get(contextOID));
502 if (jbossContext != null)
503 jbossContext.unbind(ncx);
504 else
505 NamingContextExtHelper.narrow(context).unbind(ncx);
506 }
507 }
508
509 //======================================= NamingContextExtOperations Methods ==================================//
510
511 public org.omg.CORBA.Object resolve_str(String n) throws NotFound, CannotProceed, InvalidName {
512 return resolve(to_name(n));
513 }
514
515 public NameComponent[] to_name(String sn) throws InvalidName {
516 return Name.toName(sn);
517 }
518
519 public String to_string(NameComponent[] n) throws InvalidName {
520 return Name.toString(n);
521 }
522
523 public String to_url(String addr, String sn) throws InvalidAddress, InvalidName {
524 org.jacorb.orb.util.CorbaLoc corbaLoc;
525 try {
526 corbaLoc = new org.jacorb.orb.util.CorbaLoc((org.jacorb.orb.ORB) orb, addr);
527 return corbaLoc.toCorbaName(sn);
528 } catch (IllegalArgumentException ia) {
529 throw new InvalidAddress();
530 }
531 }
532
533 //======================================= Private Helper Methods ==================================//
534
535 /**
536 * <p>
537 * Cleanup bindings, i.e. ping every object and remove bindings to non-existent objects.
538 * </p>
539 */
540 private void cleanup() {
541 // Check if object purging enabled
542 if (!this.doPurge)
543 return;
544
545 for (Name key : this.names.keySet()) {
546 if (isDead(((org.omg.CORBA.Object) this.names.get(key)))) {
547 this.names.remove(key);
548 }
549 }
550
551 for (Name key : this.contexts.keySet()) {
552 org.omg.CORBA.Object object = (org.omg.CORBA.Object) this.contexts.get(key);
553 if (isDead(object)) {
554 this.contexts.remove(key);
555 String oid = this.getObjectOID(object);
556 if (oid != null)
557 contextImpls.remove(oid);
558 }
559 }
560 }
561
562 /**
563 * <p>
564 * Obtains the OID of the specified CORBA object.
565 * </p>
566 *
567 * @param object the CORBA object whose OID is to be extracted.
568 * @return a {@code String} representing the object OID or null if the method is unable to obtain the object OID.
569 */
570 private String getObjectOID(org.omg.CORBA.Object object) {
571 String oid = null;
572 try {
573 byte[] oidBytes = this.poa.reference_to_id(object);
574 if (oidBytes != null)
575 oid = new String(oidBytes);
576 } catch (Exception e) {
577 JacORBLogger.ROOT_LOGGER.failedToObtainIdFromObject(e);
578 }
579 return oid;
580 }
581
582 /**
583 * <p>
584 * Obtains the number of bindings in this context.
585 * </p>
586 *
587 * @return the number of bindings in this context
588 */
589 private int how_many() {
590 if (this.destroyed)
591 return 0;
592 return this.names.size() + this.contexts.size();
593 }
594
595 /**
596 * <p>
597 * Determines if the supplied object is non_existent
598 * </p>
599 *
600 * @param o the CORBA object being verified.
601 * @return {@code true} if the object is non-existent; {@code false} otherwise.
602 */
603 private boolean isDead(org.omg.CORBA.Object o) {
604 boolean non_exist;
605 try {
606 non_exist = o._non_existent();
607 } catch (org.omg.CORBA.SystemException e) {
608 non_exist = true;
609 }
610 return non_exist;
611 }
612
613 /**
614 * <p>
615 * Overrides readObject in Serializable.
616 * </p>
617 *
618 * @param in the {@code InputStream} used to read the objects.
619 * @throws Exception if an error occurs while reading the objects from the stream.
620 */
621 private void readObject(ObjectInputStream in) throws Exception {
622 in.defaultReadObject();
623
624 /**
625 * Recreate tables. For serialization, object references have been transformed into strings
626 */
627 for (Name key : this.contexts.keySet()) {
628 String ref = (String) this.contexts.remove(key);
629 this.contexts.put(key, orb.string_to_object(ref));
630 }
631
632 for (Name key : this.names.keySet()) {
633 String ref = (String) this.names.remove(key);
634 this.names.put(key, orb.string_to_object(ref));
635 }
636 }
637
638 /**
639 * <p>
640 * Overrides writeObject in Serializable.
641 * </p>
642 *
643 * @param out the {@code OutputStream} where the objects will be written.
644 * @throws IOException if an error occurs while writing the objects to the stream.
645 */
646 private void writeObject(java.io.ObjectOutputStream out) throws IOException {
647 /*
648 * For serialization, object references are transformed into strings
649 */
650 for (Name key : this.contexts.keySet()) {
651 org.omg.CORBA.Object o = (org.omg.CORBA.Object) this.contexts.remove(key);
652 this.contexts.put(key, orb.object_to_string(o));
653 }
654
655 for (Name key : this.names.keySet()) {
656 org.omg.CORBA.Object o = (org.omg.CORBA.Object) this.names.remove(key);
657 this.names.put(key, orb.object_to_string(o));
658 }
659
660 out.defaultWriteObject();
661 }
662}