libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / orbd / PersistentMap.java
blob87ade64cc952d454339a3976d4a29d26cbc0f0ba
1 /* PersistentMap.java -- The persistent object naming map
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.classpath.tools.orbd;
41 import gnu.CORBA.NamingService.NamingMap;
43 import java.io.BufferedOutputStream;
44 import java.io.BufferedReader;
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.io.InputStreamReader;
50 import java.io.OutputStream;
51 import java.util.Iterator;
52 import java.util.Map;
54 import org.omg.CORBA.ORB;
55 import org.omg.CosNaming.NameComponent;
56 import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
57 import org.omg.CosNaming.NamingContextPackage.InvalidName;
59 /**
60 * The persistent object naming map for the persistent naming service. The
61 * inherited (super.) naming map implementation is transient and is used as a
62 * cache. During the normal work, the naming map does not read from the disk,
63 * just stores the changes there. Map only reads from the disk when it starts.
65 * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
67 public class PersistentMap
68 extends NamingMap
70 /**
71 * The data entry.
73 public static class Entry
75 String id;
77 String kind;
79 String ior;
81 /**
82 * Get the name component node.
84 public NameComponent getComponent()
86 return new NameComponent(id, kind);
89 /**
90 * Write the naming map entry to the output stream.
92 public void write(OutputStream out) throws IOException
94 // Format: id.kind <eoln> ior <eoln><eoln>
95 out.write(getKey(id, kind).getBytes());
96 out.write('\n');
97 out.write(ior.getBytes());
98 out.write('\n');
99 out.close();
103 * Read the name component from the input stream
105 public boolean read(BufferedReader in) throws IOException
107 String key = in.readLine();
108 String xior = in.readLine();
110 if (key != null && xior != null)
112 if (key.length() < 2)
114 // A single char key cannot have the kind part.
115 id = key;
116 kind = "";
118 else
120 // Search for the id/kind splitter, dot:
121 int iks = - 1;
122 for (int i = 1; i < key.length(); i++)
124 if (key.charAt(i) == '.')
125 // The id is separated from kind by dot, unless preceeded by
126 // the
127 // escape character, \.
128 if (key.charAt(i - 1) != '\\')
130 iks = i;
131 break;
135 // May also end by dot, if the kind field is missing.
136 if (iks < 0)
138 id = key;
139 kind = "";
141 else if (iks == key.length() - 1)
143 id = key.substring(0, key.length() - 1);
144 kind = "";
146 else
148 id = key.substring(0, iks);
149 kind = key.substring(iks + 1);
152 ior = xior;
153 return true;
155 else
156 return false;
160 * Get the key value from the name component.
162 * @param id the component id
163 * @param kind the component kind
164 * @return the key value
166 public String getKey(String id, String kind)
168 StringBuilder b = new StringBuilder(id.length() + 8);
169 appEscaping(b, id);
170 b.append('.');
171 if (kind != null && kind.length() > 0)
172 appEscaping(b, kind);
173 return b.toString();
177 * Append the contents of the string to this string buffer, inserting the
178 * escape sequences, where required.
180 * @param b a buffer to append the contents to.
181 * @param s a string to append.
183 void appEscaping(StringBuilder b, String s)
185 char c;
186 for (int i = 0; i < s.length(); i++)
188 c = s.charAt(i);
189 switch (c)
191 case '.':
192 case '/':
193 case '\\':
194 b.append('\\');
195 b.append(c);
196 break;
198 default:
199 b.append(c);
200 break;
207 * The file, where the persistent naming map stores the information. The
208 * format of this file is n*(id LF kind LF ior LFLF).
210 public final File file;
213 * The naming service ORB, used to obtain and produce the object stringified
214 * references.
216 ORB orb;
219 * If true, all existing data on the file system are discarded.
221 boolean reset;
224 * Create the persistent map that stores information in the given file.
226 * @param an_orb the naming service ORB, used to obtain and produce the object
227 * stringified references.
228 * @param mapFile the file, where the persistent information is stored.
229 * @param a_reset if true, the previous naming data are discarded. If false
230 * (normally expected), they are loaded from the persistent memory to
231 * provide the persistence.
233 public PersistentMap(ORB an_orb, File mapFile, boolean a_reset)
235 super();
236 orb = an_orb;
237 file = mapFile;
238 reset = a_reset;
240 // Initialise the persistent map with existing data.
241 if (file.exists() && ! reset)
244 BufferedReader in;
247 FileInputStream fin = new FileInputStream(file);
248 in = new BufferedReader(new InputStreamReader(fin));
249 Entry e = new Entry();
250 boolean ok;
252 while (e.read(in))
254 org.omg.CORBA .Object object = string_to_object(e.ior);
255 orb.connect(object);
256 map.put(e.getComponent(), object);
259 catch (Exception ex)
261 InternalError ierr = new InternalError(file.getAbsolutePath());
262 ierr.initCause(ex);
263 throw ierr;
269 * Restore object from its string description.
271 * @param description the string, describing the object
273 * @return the object.
275 protected org.omg.CORBA.Object string_to_object(String description)
277 return orb.string_to_object(description);
281 * Convert the object to its string description
283 * @param object the object to convert
284 * @return the string description of the object
286 protected String object_to_string(org.omg.CORBA .Object object)
288 return orb.object_to_string(object);
292 * Put the given GIOP object, specifying the given name as a key. If the entry
293 * with the given name already exists, or if the given object is already
294 * mapped under another name, the {@link AlreadyBound} exception will be
295 * thrown.
297 * @param name the name
298 * @param object the object
300 public void bind(NameComponent name, org.omg.CORBA.Object object)
301 throws AlreadyBound, InvalidName
303 if (!containsKey(name))
305 super.bind(name, object);
306 register(name, object);
308 else
309 throw new AlreadyBound(name.id + "." + name.kind);
313 * Put the given CORBA object, specifying the given name as a key. Remove all
314 * pre - existing mappings for the given name and object.
316 * @param name the name.
317 * @param object the object
319 public void rebind(NameComponent name, org.omg.CORBA.Object object)
320 throws InvalidName
322 if (containsKey(name))
324 org.omg.CORBA.Object existing = get(name);
325 String ior = object_to_string(object);
326 String xior = object_to_string(existing);
328 // Same name and same ior - nothing to do.
329 if (ior.equals(xior))
330 return;
331 else
332 remove(name);
335 Iterator iter = entries().iterator();
336 Map.Entry item;
338 // Remove the existing mapping for the given object, if present.
339 while (iter.hasNext())
341 item = (Map.Entry) iter.next();
342 if (item.getValue().equals(object))
343 iter.remove();
346 map.put(name, object);
347 register(name, object);
351 * Removes the given name, if present.
353 * @param name a name to remove.
355 public void remove(NameComponent name)
357 super.remove(name);
358 unregister(name);
362 * Register this name - object pair in the persistent storage.
364 * @param name the name.
365 * @param object the object
367 public void register(NameComponent name, org.omg.CORBA.Object object)
369 // If this key is already known, and this is the same object,
370 // then return without action.
371 String ior = object_to_string(object);
373 synchronized (file)
377 FileOutputStream fou;
379 if (! file.exists())
380 fou = new FileOutputStream(file);
381 else
382 fou = new FileOutputStream(file, true);
384 Entry e = new Entry();
385 e.id = name.id;
386 e.kind = name.kind;
387 e.ior = ior;
388 e.write(fou);
389 fou.close();
391 catch (Exception e)
393 InternalError ierr = new InternalError(file.getAbsolutePath());
394 ierr.initCause(e);
395 throw ierr;
401 * Remove this name from the persistent storage.
403 * @param name the name to remove
405 public void unregister(NameComponent name)
407 synchronized (file)
411 File nf = new File(file.getParent(), file.getName() + "_t");
412 FileInputStream fin = new FileInputStream(file);
413 FileOutputStream fou = new FileOutputStream(nf);
414 BufferedOutputStream ou = new BufferedOutputStream(fou);
416 BufferedReader in = new BufferedReader(new InputStreamReader(fin));
417 String s;
418 String nk = name.kind;
419 if (nk == null)
420 nk = "";
422 Entry e = new Entry();
424 while (e.read(in))
426 if (e.id.equals(name.id) && e.kind.equals(nk))
428 // Do nothing - skip.
430 else
432 e.write(ou);
436 File deleteIt = new File(file.getParent(), file.getName() + "_d");
437 if (deleteIt.exists())
438 deleteIt.delete();
440 if (! file.renameTo(deleteIt))
441 throw new IOException(file.getAbsolutePath() + " rename failed");
443 if (! nf.renameTo(file))
444 throw new IOException(file.getAbsolutePath() + " rename failed");
446 catch (Exception e)
448 InternalError ierr = new InternalError(file.getAbsolutePath());
449 ierr.initCause(e);
450 throw ierr;