This patch adds the persistent naming CORBA (GIOP) service, necessary to
provide support level, equal to the support level, provided by Sun (Sun calls
this tool orbd). It benefits for being part of Classpath, using gnu.CORBA.*

2006-02-14  Audrius Meskauskas  <[EMAIL PROTECTED]>

   * NEWS: Updated tool status.
   * gnu/CORBA/NamingService/NamingMap.java (Map): Made protected.
   (constructor, bind, rebind): Rewritten.
   * gnu/CORBA/NamingService/TransientContext.java: Rewritten.
   * tools/gnu/classpath/tools/giop/README: Updated.
   * tools/gnu/classpath/tools/giop/NameServicePersistent.java,
   tools/gnu/classpath/tools/giop/NamingServicePersistent.txt,
   tools/gnu/classpath/tools/giop/nameservice/PersistentContext.java,
   tools/gnu/classpath/tools/giop/nameservice/PersistentContextMap.java,
tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java: New files.
Index: NEWS
===================================================================
RCS file: /sources/classpath/classpath/NEWS,v
retrieving revision 1.110
diff -u -r1.110 NEWS
--- NEWS	13 Feb 2006 19:13:15 -0000	1.110
+++ NEWS	14 Feb 2006 15:02:32 -0000
@@ -9,8 +9,8 @@
  
 * The new folder tools now contains GIOP and RMI tools, providing necessary
   support for development using org.omg.*, javax.rmi.CORBA.* and java.rmi.* 
-  packages. The toll set includes GIOP and RMI stub and tie code generators,
-  IOR parser and GIOP naming service. 
+  packages. The toll set includes GIOP and RMI stub and tie source code
+  generators, IOR parser and both transient and persistent GIOP naming services. 
 
 * RELAX NG pluggable XML schema datatype library API and an implementation
   for XML Schema Datatypes (http://www.w3.org/TR/xmlschema-2/).
Index: gnu/CORBA/NamingService/NamingMap.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/CORBA/NamingService/NamingMap.java,v
retrieving revision 1.3
diff -u -r1.3 NamingMap.java
--- gnu/CORBA/NamingService/NamingMap.java	28 Oct 2005 14:05:21 -0000	1.3
+++ gnu/CORBA/NamingService/NamingMap.java	14 Feb 2006 15:02:37 -0000
@@ -58,11 +58,11 @@
   /**
    * The actual map.
    */
-  private final TreeMap map;
+  protected final TreeMap map;
 
   /**
    * Creates an instance of the naming map, intialising the comparator
-   * to the [EMAIL PROTECTED] cmpNameComparator}.
+   * to the [EMAIL PROTECTED] NameComponentComparator}.
    */
   public NamingMap()
   {
@@ -70,7 +70,7 @@
   }
 
   /**
-   * Put the given CORBA object, specifying the given name as a key.
+   * Put the given GIOP object, specifying the given name as a key.
    * If the entry with the given name already exists, or if the given
    * object is already mapped under another name, the
    * [EMAIL PROTECTED] AlreadyBound} exception will be thrown.
@@ -93,8 +93,11 @@
     else
       {
         if (containsValue(object))
-          throw new AlreadyBound("Tha object has another name");
+          throw new AlreadyBound("The object has another name");
       }
+    
+    // There are no restrictions in binding the object.
+    rebind(name, object);
   }
 
   /**
@@ -141,7 +144,7 @@
   }
 
   /**
-   * Put the given CORBA object, specifying the given name as a key.
+   * Put the given GIOP object, specifying the given name as a key.
    * Remove all pre - existing mappings for the given name and object.
    *
    * @param name the name.
Index: gnu/CORBA/NamingService/TransientContext.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/CORBA/NamingService/TransientContext.java,v
retrieving revision 1.2
diff -u -r1.2 TransientContext.java
--- gnu/CORBA/NamingService/TransientContext.java	2 Jul 2005 20:32:09 -0000	1.2
+++ gnu/CORBA/NamingService/TransientContext.java	14 Feb 2006 15:02:37 -0000
@@ -59,7 +59,7 @@
 
 /**
  * This class implements the transient naming service, defined by
- * [EMAIL PROTECTED] NamingContex}. The 'transient' means that the service does
+ * [EMAIL PROTECTED] NamingContext}. The 'transient' means that the service does
  * not store its state into the persistent memory. If the service is
  * restarted, the named objects must be re-registered again.
  *
@@ -72,14 +72,39 @@
   implements NamingContext, NamingContextOperations
 {
   /**
+   * Use serial version UID for interoperability.
+   */
+  private static final long serialVersionUID = 2;
+  
+  /**
    * The already named contexts.
    */
-  protected final NamingMap named_contexts = new NamingMap();
+  protected final NamingMap named_contexts;
 
   /**
    * The already named objects.
    */
-  protected final NamingMap named_objects = new NamingMap();
+  protected final NamingMap named_objects;
+  
+  /**
+   * Create the naming conetxt with default (transient) naming maps.
+   */
+  public TransientContext()
+  {
+    this(new NamingMap(), new NamingMap());
+  }
+  
+  /**
+   * Create the naming conetxt with the two provided naming maps.
+   * 
+   * @param context_map the map for contexts
+   * @param object_map the map for objectss
+   */
+  public TransientContext(NamingMap context_map, NamingMap object_map)
+  {
+    named_contexts = context_map;
+    named_objects = object_map;
+  }
 
   /**
    * Gives the object a name, valid in this context.
@@ -376,7 +401,7 @@
   /**
    * Create a binding.
    *
-   * @param entry the entry, defining the bound object.
+   * @param an_entry the entry, defining the bound object.
    * @param type the binding type.
    * @return the created binding.
    */
@@ -396,7 +421,7 @@
    * name, and pass the remainder (without the first node)
    * of the name for that context to resolve.
    *
-   * @param name the name to resolve.
+   * @param a_name the name to resolve.
    *
    * @return the resolved context
    */
Index: tools/gnu/classpath/tools/giop/README
===================================================================
RCS file: /sources/classpath/classpath/tools/gnu/classpath/tools/giop/README,v
retrieving revision 1.2
diff -u -r1.2 README
--- tools/gnu/classpath/tools/giop/README	8 Feb 2006 12:14:05 -0000	1.2
+++ tools/gnu/classpath/tools/giop/README	14 Feb 2006 15:03:06 -0000
@@ -7,7 +7,12 @@
 The list of the currently available tools:
 
 * GRMIC -                RMI-IIOP stub and tie generator.
-* NameService  -         GIOP naming service (currently transient, but the
-                         persistent fuctionality may be added in the future).
+* NameService  -         GIOP transient naming service (this tool is called 
+                         tnameserv in Sun's package).
+* NameService  -         GIOP persistent naming service (this tool is called 
+                         orbd in Sun's package).
 * IorParser -            Parses the stringified form of the interoperable 
-                         object references (IOR's).
\ No newline at end of file
+                         object references (IOR's).
+* RMIC -                 RMI stub and tie source code generator (complements
+                         the ASM based bytecode generator in the separate
+                         tools package).
\ No newline at end of file
Index: tools/gnu/classpath/tools/giop/NameServicePersistent.java
===================================================================
RCS file: tools/gnu/classpath/tools/giop/NameServicePersistent.java
diff -N tools/gnu/classpath/tools/giop/NameServicePersistent.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/gnu/classpath/tools/giop/NameServicePersistent.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,186 @@
+/* NamingServicePersistent.java -- The persistent naming service.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.giop;
+
+import gnu.CORBA.OrbFunctional;
+import gnu.CORBA.IOR;
+import gnu.CORBA.NamingService.Ext;
+import gnu.classpath.tools.HelpPrinter;
+import gnu.classpath.tools.giop.nameservice.PersistentContext;
+
+import org.omg.CosNaming.NamingContextExt;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * The server for the gnu classpath persistent naming service. 
+ * 
+ * GNU Classpath currently works with this naming service and is also
+ * interoperable with the Sun Microsystems naming services from releases 1.3 and
+ * 1.4, both transient <i>tnameserv</i> and persistent <i>orbd</i>.
+ * 
+ * @author Audrius Meskauskas, Lithuania ([EMAIL PROTECTED])
+ */
+public class NameServicePersistent
+{
+  /**
+   * The default port (900), on that the naming service starts if no
+   * -ORBInitialPort is specified in the command line.
+   */
+  public static final int PORT = 900;
+
+  /**
+   * Get the object key for the naming service. The default key is the string
+   * "NameService" in ASCII.
+   * 
+   * @return the byte array.
+   */
+  public static byte[] getDefaultKey()
+  {
+    try
+      { // NameService
+        return "NameService".getBytes("UTF-8");
+      }
+    catch (UnsupportedEncodingException ex)
+      {
+        throw new InternalError("UTF-8 unsupported");
+      }
+  }
+
+  /**
+   * Start the naming service on the current host at the given port. The
+   * parameter -org.omg.CORBA.ORBInitialPort NNN or -ORBInitialPort NNN, if
+   * present, specifies the port, on that the service must be started. If this
+   * key is not specified, the service starts at the port 900. The parameter
+   * -ior FILE_NAME, if present, forces to store the ior string of this naming
+   * service to the specified file.
+   * 
+   * @param args the parameter string.
+   */
+  public static void main(String[] args)
+  {
+    HelpPrinter.checkHelpKey(args, "giop/NamingServicePersistent.txt");
+    System.out.println("Please use --help for options.");
+
+    int port = PORT;
+    String iorf = null;
+    boolean reset = false;
+    String folder = "";
+    try
+      {
+        // Create and initialize the ORB
+        final OrbFunctional orb = new OrbFunctional();
+
+        for (int i = 0; i < args.length; i++)
+          {
+            if (i < args.length - 1)
+              {
+                if (args[i].endsWith("ORBInitialPort"))
+                  port = Integer.parseInt(args[i + 1]);
+
+                if (args[i].equals("-ior"))
+                  iorf = args[i + 1];
+
+                if (args[i].equals("-folder"))
+                  folder = args[i + 1];
+              }
+            if (args[i].equals("-reset"))
+              reset = true;
+          }
+
+        OrbFunctional.setPort(port);
+
+        // Create the servant and register it with the ORB
+        File dataFolder = new File(folder);
+        System.out.println("Persistent data stored at "
+                           + dataFolder.getAbsolutePath());
+        dataFolder.mkdirs();
+
+        // / TODO support more starting modes.
+        NamingContextExt namer = new Ext(
+                                         new PersistentContext(
+                                                               orb,
+                                                               dataFolder,
+                                                               reset));
+
+        // Case with the key "NameService".
+        orb.connect(namer, "NameService".getBytes());
+
+        // Storing the IOR reference.
+        String ior = orb.object_to_string(namer);
+        IOR iorr = IOR.parse(ior);
+        if (iorf != null)
+          {
+            FileOutputStream f = new FileOutputStream(iorf);
+            PrintStream p = new PrintStream(f);
+            p.print(ior);
+            p.close();
+          }
+
+        System.out.println("GNU Classpath persistent naming service "
+                           + "started at " + iorr.Internet.host + ":"
+                           + iorr.Internet.port + " key 'NameService'.\n\n"
+                           + "Copyright (C) 2006 Free Software Foundation\n"
+                           + "This tool comes with ABSOLUTELY NO WARRANTY. "
+                           + "This is free software, and you are\nwelcome to "
+                           + "redistribute it under conditions, defined in "
+                           + "GNU Classpath license.\n\n" + ior);
+
+        new Thread()
+        {
+          public void run()
+          {
+            // Wait for invocations from clients.
+            orb.run();
+          }
+        }.start();
+      }
+    catch (Exception e)
+      {
+        System.err.println("ERROR: " + e);
+        e.printStackTrace(System.out);
+      }
+
+    // Restore the default value for allocating ports for the subsequent
+    // objects.
+    OrbFunctional.setPort(OrbFunctional.DEFAULT_INITIAL_PORT);
+  }
+}
Index: tools/gnu/classpath/tools/giop/NamingServicePersistent.txt
===================================================================
RCS file: tools/gnu/classpath/tools/giop/NamingServicePersistent.txt
diff -N tools/gnu/classpath/tools/giop/NamingServicePersistent.txt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/gnu/classpath/tools/giop/NamingServicePersistent.txt	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,26 @@
+Copyright 2006 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Please report bugs at http://www.gnu.org/software/classpath/bugs.html
+
+GNU Classpath GIOP persitent naming service.
+  usage: NameServicePersistent <options>
+
+ where <options> includes:
+* -org.omg.CORBA.ORBInitialPort NNN
+ or -ORBInitialPort NNN          - specifies the port, on that the 
+                                   service must be started. If this key
+                                   is not specified, the service starts
+                                   at the port 900.
+   
+* -ior FILE_NAME                - store the IOR reference to this naming 
+                                  service to the specified file. The
+                                  IOR reference contains enough 
+                                  information to locate the service
+                                  on the web.
+* - folder FOLDER               - store the persistent information
+                                  to the given folder
+* - reset                       - discard any previously stored
+                                  persistent information (cold start)                                          
+
Index: tools/gnu/classpath/tools/giop/nameservice/PersistentContext.java
===================================================================
RCS file: tools/gnu/classpath/tools/giop/nameservice/PersistentContext.java
diff -N tools/gnu/classpath/tools/giop/nameservice/PersistentContext.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/gnu/classpath/tools/giop/nameservice/PersistentContext.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,152 @@
+/* PersistentContext.java -- The persistent naming context.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.giop.nameservice;
+
+import gnu.CORBA.NamingService.NameTransformer;
+import gnu.CORBA.NamingService.TransientContext;
+
+import java.io.File;
+
+import org.omg.CORBA.ORB;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContext;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+
+/**
+ * This class implements the persistent naming service, defined by
+ * [EMAIL PROTECTED] NamingContext}. The 'persistent' means that the service remembers the
+ * mappings, stored between restarts.
+ * 
+ * @author Audrius Meskauskas, Lithuania ([EMAIL PROTECTED])
+ */
+public class PersistentContext
+    extends TransientContext
+{
+  /**
+   * Use serial version UID for interoperability.
+   */
+  private static final long serialVersionUID = 2;
+  
+  /**
+   * The folder, where the persistent context information is stored.
+   */
+  File contextFolder;
+  
+  /**
+   * The uinque context identifier.
+   */
+  static long num = System.currentTimeMillis();
+  
+  /**
+   * The naming service orb.
+   */
+  ORB orb;
+  
+  /**
+   * Create the persistent naming context that will store the files in the given
+   * folder of the local file system. This method also connects object to the
+   * passed ORB.
+   * 
+   * @param an_orb the naming service ORB, used to obtain and produce the object
+   *          stringified references.
+   * @param folder the folder, where the persistent information is stored.
+   * @param reset if true, the previous naming data are discarded. If false
+   *          (normally expected), they are loaded from the persistent memory to
+   *          provide the persistence.
+   */
+  public PersistentContext(ORB an_orb, File folder, boolean reset)
+  {
+    super(
+         new PersistentContextMap(an_orb, new File(folder, "contexts.txt"), reset),
+         new PersistentMap(an_orb, new File(folder, "objects.txt"), reset));         
+    contextFolder = folder;
+    folder.mkdirs();
+    orb = an_orb;
+    orb.connect(this);
+  }
+  
+  /**
+   * Get the unique context number;
+   * 
+   * @return the context number
+   */
+  static synchronized String getNum()
+  {
+    return Long.toHexString(num++);
+  }
+  
+  /**
+   * Create new persistent context.
+   */
+  public NamingContext new_context()
+  {
+    File ctxFolder = new File(contextFolder, "ctx_"+getNum());
+    return new PersistentContext(orb, ctxFolder, true);
+  }
+  
+  /**
+   * Create a new context and give it a given name (bound it) in the current
+   * context. The method benefits from passing the better readable context name.
+   * 
+   * @param a_name the name being given to the new context.
+   * @return the newly created context.
+   * @throws AlreadyBound if the name is already in use.
+   * @throws InvalidName if the name has zero length or otherwise invalid.
+   */
+  public NamingContext bind_new_context(NameComponent[] a_name)
+      throws NotFound, AlreadyBound, CannotProceed, InvalidName
+  {
+    if (named_contexts.containsKey(a_name[0])
+        || named_objects.containsKey(a_name[0]))
+      throw new AlreadyBound();
+
+    NameTransformer transformer = new NameTransformer();
+
+    File ctxFolder = new File(contextFolder,
+                              transformer.toString(a_name).replace('/', '.')
+                                  + ".v" + getNum());
+
+    NamingContext child = new PersistentContext(orb, ctxFolder, true);
+    bind_context(a_name, child);
+    return child;
+  }  
+}
Index: tools/gnu/classpath/tools/giop/nameservice/PersistentContextMap.java
===================================================================
RCS file: tools/gnu/classpath/tools/giop/nameservice/PersistentContextMap.java
diff -N tools/gnu/classpath/tools/giop/nameservice/PersistentContextMap.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/gnu/classpath/tools/giop/nameservice/PersistentContextMap.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,87 @@
+/* PersistentContextMap.java -- The persistent context naming map
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.giop.nameservice;
+
+import java.io.File;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Object;
+
+/**
+ * The persistent context naming map for the persistent naming service. 
+ * 
+ * @author Audrius Meskauskas, Lithuania ([EMAIL PROTECTED])
+ */
+public class PersistentContextMap extends PersistentMap
+{
+  /**
+   * Create the persistent context map that stores information in the given
+   * file.
+   * 
+   * @param an_orb the naming service ORB, used to obtain and produce the object
+   *          stringified references.
+   * @param mapFile the file, where the persistent information is stored.
+   * @param reset if true, the previous naming data are discarded. If false
+   *          (normally expected), they are loaded from the persistent memory to
+   *          provide the persistence.
+   */
+  public PersistentContextMap(ORB an_orb, File mapFile, boolean reset)
+  {
+    super(an_orb, mapFile, reset);
+  }
+
+  /**
+   * This method expects the PersistentContext as its parameter. The returned
+   * description line is the name of the context parent folder.
+   */
+  protected String object_to_string(Object object)
+  {
+    PersistentContext pc = (PersistentContext) object;
+    return pc.contextFolder.getAbsolutePath();
+  }
+
+  /**
+   * This method restores the PersistenContext. The description line is
+   * interpreted as the folder name, absolute path.
+   */
+  protected Object string_to_object(String description)
+  {
+    return new PersistentContext(orb, new File(description), reset);
+  }
+}
Index: tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java
===================================================================
RCS file: tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java
diff -N tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,454 @@
+/* PersistentMap.java -- The persistent object naming map
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.giop.nameservice;
+
+import gnu.CORBA.NamingService.NamingMap;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.omg.CORBA.ORB;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+
+/**
+ * The persistent object naming map for the persistent naming service. The
+ * inherited (super.) naming map implementation is transient and is used as a
+ * cache. During the normal work, the naming map does not read from the disk,
+ * just stores the changes there. Map only reads from the disk when it starts.
+ * 
+ * @author Audrius Meskauskas, Lithuania ([EMAIL PROTECTED])
+ */
+public class PersistentMap
+    extends NamingMap
+{
+  /**
+   * The data entry.
+   */
+  public static class Entry
+  {
+    String id;
+
+    String kind;
+
+    String ior;
+
+    /**
+     * Get the name component node.
+     */
+    public NameComponent getComponent()
+    {
+      return new NameComponent(id, kind);
+    }
+
+    /**
+     * Write the naming map entry to the output stream.
+     */
+    public void write(OutputStream out) throws IOException
+    {
+      // Format: id.kind <eoln> ior <eoln><eoln>
+      out.write(getKey(id, kind).getBytes());
+      out.write('\n');
+      out.write(ior.getBytes());
+      out.write('\n');
+      out.close();
+    }
+
+    /**
+     * Read the name component from the input stream
+     */
+    public boolean read(BufferedReader in) throws IOException
+    {
+      String key = in.readLine();
+      String xior = in.readLine();
+
+      if (key != null && xior != null)
+        {
+          if (key.length() < 2)
+            {
+              // A single char key cannot have the kind part.
+              id = key;
+              kind = "";
+            }
+          else
+            {
+              // Search for the id/kind splitter, dot:
+              int iks = - 1;
+              for (int i = 1; i < key.length(); i++)
+                {
+                  if (key.charAt(i) == '.')
+                    // The id is separated from kind by dot, unless preceeded by
+                    // the
+                    // escape character, \.
+                    if (key.charAt(i - 1) != '\\')
+                      {
+                        iks = i;
+                        break;
+                      }
+                }
+
+              // May also end by dot, if the kind field is missing.
+              if (iks < 0)
+                {
+                  id = key;
+                  kind = "";
+                }
+              else if (iks == key.length() - 1)
+                {
+                  id = key.substring(0, key.length() - 1);
+                  kind = "";
+                }
+              else
+                {
+                  id = key.substring(0, iks);
+                  kind = key.substring(iks + 1);
+                }
+            }
+          ior = xior;
+          return true;
+        }
+      else
+        return false;
+    }
+
+    /**
+     * Get the key value from the name component.
+     * 
+     * @param id the component id
+     * @param kind the component kind
+     * @return the key value
+     */
+    public String getKey(String id, String kind)
+    {
+      StringBuffer b = new StringBuffer(id.length() + 8);
+      appEscaping(b, id);
+      b.append('.');
+      if (kind != null && kind.length() > 0)
+        appEscaping(b, kind);
+      return b.toString();
+    }
+
+    /**
+     * Append the contents of the string to this string buffer, inserting the
+     * escape sequences, where required.
+     * 
+     * @param b a buffer to append the contents to.
+     * @param s a string to append.
+     */
+    void appEscaping(StringBuffer b, String s)
+    {
+      char c;
+      for (int i = 0; i < s.length(); i++)
+        {
+          c = s.charAt(i);
+          switch (c)
+            {
+            case '.':
+            case '/':
+            case '\\':
+              b.append('\\');
+              b.append(c);
+              break;
+
+            default:
+              b.append(c);
+              break;
+            }
+        }
+    }
+  }
+
+  /**
+   * The file, where the persistent naming map stores the information. The
+   * format of this file is n*(id LF kind LF ior LFLF).
+   */
+  public final File file;
+
+  /**
+   * The naming service ORB, used to obtain and produce the object stringified
+   * references.
+   */
+  ORB orb;
+  
+  /**
+   * If true, all existing data on the file system are discarded.
+   */
+  boolean reset;
+
+  /**
+   * Create the persistent map that stores information in the given file.
+   * 
+   * @param an_orb the naming service ORB, used to obtain and produce the object
+   *          stringified references.
+   * @param mapFile the file, where the persistent information is stored.
+   * @param a_reset if true, the previous naming data are discarded. If false
+   *          (normally expected), they are loaded from the persistent memory to
+   *          provide the persistence.
+   */
+  public PersistentMap(ORB an_orb, File mapFile, boolean a_reset)
+  {
+    super();
+    orb = an_orb;
+    file = mapFile;
+    reset = a_reset;
+
+    // Initialise the persistent map with existing data.
+    if (file.exists() && ! reset)
+      {
+
+        BufferedReader in;
+        try
+          {
+            FileInputStream fin = new FileInputStream(file);
+            in = new BufferedReader(new InputStreamReader(fin));
+            Entry e = new Entry();
+            boolean ok;
+
+            while (e.read(in))
+              {
+                org.omg.CORBA .Object object = string_to_object(e.ior);
+                orb.connect(object);
+                map.put(e.getComponent(), object);
+              }
+          }
+        catch (Exception ex)
+          {
+            InternalError ierr = new InternalError(file.getAbsolutePath());
+            ierr.initCause(ex);
+            throw ierr;
+          }
+      }
+  }
+  
+  /**
+   * Restore object from its string description.
+   * 
+   * @param description the string, describing the object
+   * 
+   * @return the object.
+   */
+  protected org.omg.CORBA.Object string_to_object(String description)
+  {
+    return orb.string_to_object(description);
+  }
+  
+  /**
+   * Convert the object to its string description
+   * 
+   * @param object the object to convert
+   * @return the string description of the object
+   */
+  protected String object_to_string(org.omg.CORBA .Object object)
+  {
+      return orb.object_to_string(object);    
+  }
+
+  /**
+   * Put the given GIOP object, specifying the given name as a key. If the entry
+   * with the given name already exists, or if the given object is already
+   * mapped under another name, the [EMAIL PROTECTED] AlreadyBound} exception will be
+   * thrown.
+   * 
+   * @param name the name
+   * @param object the object
+   */
+  public void bind(NameComponent name, org.omg.CORBA.Object object)
+      throws AlreadyBound, InvalidName
+  {
+    if (!containsKey(name))
+      {
+        super.bind(name, object);
+        register(name, object);
+      }
+    else
+      throw new AlreadyBound(name.id + "." + name.kind);
+  }
+
+  /**
+   * Put the given CORBA object, specifying the given name as a key. Remove all
+   * pre - existing mappings for the given name and object.
+   * 
+   * @param name the name.
+   * @param object the object
+   */
+  public void rebind(NameComponent name, org.omg.CORBA.Object object)
+      throws InvalidName
+  {
+    if (containsKey(name))
+      {
+        org.omg.CORBA.Object existing = get(name);
+        String ior = object_to_string(object);
+        String xior = object_to_string(existing);
+        
+        // Same name and same ior - nothing to do.
+        if (ior.equals(xior))
+          return;
+        else
+          remove(name);
+      }
+
+    Iterator iter = entries().iterator();
+    Map.Entry item;
+
+    // Remove the existing mapping for the given object, if present.
+    while (iter.hasNext())
+      {
+        item = (Map.Entry) iter.next();
+        if (item.getValue().equals(object))
+          iter.remove();
+      }
+
+    map.put(name, object);
+    register(name, object);
+  }
+
+  /**
+   * Removes the given name, if present.
+   * 
+   * @param name a name to remove.
+   */
+  public void remove(NameComponent name)
+  {
+    super.remove(name);
+    unregister(name);
+  }
+
+  /**
+   * Register this name - object pair in the persistent storage.
+   * 
+   * @param name the name.
+   * @param object the object
+   */
+  public void register(NameComponent name, org.omg.CORBA.Object object)
+  {
+    // If this key is already known, and this is the same object,
+    // then return without action.
+    String ior = object_to_string(object);
+
+    synchronized (file)
+      {
+        try
+          {
+            FileOutputStream fou;
+
+            if (! file.exists())
+              fou = new FileOutputStream(file);
+            else
+              fou = new FileOutputStream(file, true);
+
+            Entry e = new Entry();
+            e.id = name.id;
+            e.kind = name.kind;
+            e.ior = ior;
+            e.write(fou);
+            fou.close();
+          }
+        catch (Exception e)
+          {
+            InternalError ierr = new InternalError(file.getAbsolutePath());
+            ierr.initCause(e);
+            throw ierr;
+          }
+      }
+  }
+
+  /**
+   * Remove this name from the persistent storage.
+   * 
+   * @param name the name to remove
+   */
+  public void unregister(NameComponent name)
+  {
+    synchronized (file)
+      {
+        try
+          {
+            File nf = new File(file.getParent(), file.getName() + "_t");
+            FileInputStream fin = new FileInputStream(file);
+            FileOutputStream fou = new FileOutputStream(nf);
+            BufferedOutputStream ou = new BufferedOutputStream(fou);
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(fin));
+            String s;
+            String nk = name.kind;
+            if (nk == null)
+              nk = "";
+
+            Entry e = new Entry();
+
+            while (e.read(in))
+              {
+                if (e.id.equals(name.id) && e.kind.equals(nk))
+                  {
+                    // Do nothing - skip.
+                  }
+                else
+                  {
+                    e.write(ou);
+                  }
+              }
+
+            File deleteIt = new File(file.getParent(), file.getName() + "_d");
+            if (deleteIt.exists())
+              deleteIt.delete();
+
+            if (! file.renameTo(deleteIt))
+              throw new IOException(file.getAbsolutePath() + " rename failed");
+
+            if (! nf.renameTo(file))
+              throw new IOException(file.getAbsolutePath() + " rename failed");
+          }
+        catch (Exception e)
+          {
+            InternalError ierr = new InternalError(file.getAbsolutePath());
+            ierr.initCause(e);
+            throw ierr;
+          }
+      }
+  }
+}

Reply via email to