PageRenderTime 146ms CodeModel.GetById 42ms app.highlight 84ms RepoModel.GetById 2ms app.codeStats 0ms

/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}