OSDN Git Service

* config/i386/i386.md (*sinxf2): Rename to *sinxf2_i387.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / tools / gnu / classpath / tools / giop / nameservice / PersistentMap.java
1 /* PersistentMap.java -- The persistent object naming map
2  Copyright (C) 2006 Free Software Foundation, Inc.
3
4  This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38
39 package gnu.classpath.tools.giop.nameservice;
40
41 import gnu.CORBA.NamingService.NamingMap;
42
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;
53
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;
58
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.
64  * 
65  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
66  */
67 public class PersistentMap
68     extends NamingMap
69 {
70   /**
71    * The data entry.
72    */
73   public static class Entry
74   {
75     String id;
76
77     String kind;
78
79     String ior;
80
81     /**
82      * Get the name component node.
83      */
84     public NameComponent getComponent()
85     {
86       return new NameComponent(id, kind);
87     }
88
89     /**
90      * Write the naming map entry to the output stream.
91      */
92     public void write(OutputStream out) throws IOException
93     {
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();
100     }
101
102     /**
103      * Read the name component from the input stream
104      */
105     public boolean read(BufferedReader in) throws IOException
106     {
107       String key = in.readLine();
108       String xior = in.readLine();
109
110       if (key != null && xior != null)
111         {
112           if (key.length() < 2)
113             {
114               // A single char key cannot have the kind part.
115               id = key;
116               kind = "";
117             }
118           else
119             {
120               // Search for the id/kind splitter, dot:
121               int iks = - 1;
122               for (int i = 1; i < key.length(); i++)
123                 {
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) != '\\')
129                       {
130                         iks = i;
131                         break;
132                       }
133                 }
134
135               // May also end by dot, if the kind field is missing.
136               if (iks < 0)
137                 {
138                   id = key;
139                   kind = "";
140                 }
141               else if (iks == key.length() - 1)
142                 {
143                   id = key.substring(0, key.length() - 1);
144                   kind = "";
145                 }
146               else
147                 {
148                   id = key.substring(0, iks);
149                   kind = key.substring(iks + 1);
150                 }
151             }
152           ior = xior;
153           return true;
154         }
155       else
156         return false;
157     }
158
159     /**
160      * Get the key value from the name component.
161      * 
162      * @param id the component id
163      * @param kind the component kind
164      * @return the key value
165      */
166     public String getKey(String id, String kind)
167     {
168       StringBuffer b = new StringBuffer(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();
174     }
175
176     /**
177      * Append the contents of the string to this string buffer, inserting the
178      * escape sequences, where required.
179      * 
180      * @param b a buffer to append the contents to.
181      * @param s a string to append.
182      */
183     void appEscaping(StringBuffer b, String s)
184     {
185       char c;
186       for (int i = 0; i < s.length(); i++)
187         {
188           c = s.charAt(i);
189           switch (c)
190             {
191             case '.':
192             case '/':
193             case '\\':
194               b.append('\\');
195               b.append(c);
196               break;
197
198             default:
199               b.append(c);
200               break;
201             }
202         }
203     }
204   }
205
206   /**
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).
209    */
210   public final File file;
211
212   /**
213    * The naming service ORB, used to obtain and produce the object stringified
214    * references.
215    */
216   ORB orb;
217   
218   /**
219    * If true, all existing data on the file system are discarded.
220    */
221   boolean reset;
222
223   /**
224    * Create the persistent map that stores information in the given file.
225    * 
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.
232    */
233   public PersistentMap(ORB an_orb, File mapFile, boolean a_reset)
234   {
235     super();
236     orb = an_orb;
237     file = mapFile;
238     reset = a_reset;
239
240     // Initialise the persistent map with existing data.
241     if (file.exists() && ! reset)
242       {
243
244         BufferedReader in;
245         try
246           {
247             FileInputStream fin = new FileInputStream(file);
248             in = new BufferedReader(new InputStreamReader(fin));
249             Entry e = new Entry();
250             boolean ok;
251
252             while (e.read(in))
253               {
254                 org.omg.CORBA .Object object = string_to_object(e.ior);
255                 orb.connect(object);
256                 map.put(e.getComponent(), object);
257               }
258           }
259         catch (Exception ex)
260           {
261             InternalError ierr = new InternalError(file.getAbsolutePath());
262             ierr.initCause(ex);
263             throw ierr;
264           }
265       }
266   }
267   
268   /**
269    * Restore object from its string description.
270    * 
271    * @param description the string, describing the object
272    * 
273    * @return the object.
274    */
275   protected org.omg.CORBA.Object string_to_object(String description)
276   {
277     return orb.string_to_object(description);
278   }
279   
280   /**
281    * Convert the object to its string description
282    * 
283    * @param object the object to convert
284    * @return the string description of the object
285    */
286   protected String object_to_string(org.omg.CORBA .Object object)
287   {
288       return orb.object_to_string(object);    
289   }
290
291   /**
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.
296    * 
297    * @param name the name
298    * @param object the object
299    */
300   public void bind(NameComponent name, org.omg.CORBA.Object object)
301       throws AlreadyBound, InvalidName
302   {
303     if (!containsKey(name))
304       {
305         super.bind(name, object);
306         register(name, object);
307       }
308     else
309       throw new AlreadyBound(name.id + "." + name.kind);
310   }
311
312   /**
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.
315    * 
316    * @param name the name.
317    * @param object the object
318    */
319   public void rebind(NameComponent name, org.omg.CORBA.Object object)
320       throws InvalidName
321   {
322     if (containsKey(name))
323       {
324         org.omg.CORBA.Object existing = get(name);
325         String ior = object_to_string(object);
326         String xior = object_to_string(existing);
327         
328         // Same name and same ior - nothing to do.
329         if (ior.equals(xior))
330           return;
331         else
332           remove(name);
333       }
334
335     Iterator iter = entries().iterator();
336     Map.Entry item;
337
338     // Remove the existing mapping for the given object, if present.
339     while (iter.hasNext())
340       {
341         item = (Map.Entry) iter.next();
342         if (item.getValue().equals(object))
343           iter.remove();
344       }
345
346     map.put(name, object);
347     register(name, object);
348   }
349
350   /**
351    * Removes the given name, if present.
352    * 
353    * @param name a name to remove.
354    */
355   public void remove(NameComponent name)
356   {
357     super.remove(name);
358     unregister(name);
359   }
360
361   /**
362    * Register this name - object pair in the persistent storage.
363    * 
364    * @param name the name.
365    * @param object the object
366    */
367   public void register(NameComponent name, org.omg.CORBA.Object object)
368   {
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);
372
373     synchronized (file)
374       {
375         try
376           {
377             FileOutputStream fou;
378
379             if (! file.exists())
380               fou = new FileOutputStream(file);
381             else
382               fou = new FileOutputStream(file, true);
383
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();
390           }
391         catch (Exception e)
392           {
393             InternalError ierr = new InternalError(file.getAbsolutePath());
394             ierr.initCause(e);
395             throw ierr;
396           }
397       }
398   }
399
400   /**
401    * Remove this name from the persistent storage.
402    * 
403    * @param name the name to remove
404    */
405   public void unregister(NameComponent name)
406   {
407     synchronized (file)
408       {
409         try
410           {
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);
415
416             BufferedReader in = new BufferedReader(new InputStreamReader(fin));
417             String s;
418             String nk = name.kind;
419             if (nk == null)
420               nk = "";
421
422             Entry e = new Entry();
423
424             while (e.read(in))
425               {
426                 if (e.id.equals(name.id) && e.kind.equals(nk))
427                   {
428                     // Do nothing - skip.
429                   }
430                 else
431                   {
432                     e.write(ou);
433                   }
434               }
435
436             File deleteIt = new File(file.getParent(), file.getName() + "_d");
437             if (deleteIt.exists())
438               deleteIt.delete();
439
440             if (! file.renameTo(deleteIt))
441               throw new IOException(file.getAbsolutePath() + " rename failed");
442
443             if (! nf.renameTo(file))
444               throw new IOException(file.getAbsolutePath() + " rename failed");
445           }
446         catch (Exception e)
447           {
448             InternalError ierr = new InternalError(file.getAbsolutePath());
449             ierr.initCause(e);
450             throw ierr;
451           }
452       }
453   }
454 }