diff options
Diffstat (limited to 'tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java')
-rw-r--r-- | tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java b/tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java new file mode 100644 index 000000000..6939ede17 --- /dev/null +++ b/tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java @@ -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 (AudriusA@Bioinformatics.org) + */ +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 {@link 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; + } + } + } +} |