OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / javax / naming / jndi / url / rmi / ContextContinuation.java
1 /* ContextContinuation.java -- RMI naming context
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 package gnu.javax.naming.jndi.url.rmi;
39
40 import java.rmi.AccessException;
41 import java.rmi.AlreadyBoundException;
42 import java.rmi.NotBoundException;
43 import java.rmi.Remote;
44 import java.rmi.RemoteException;
45 import java.rmi.registry.LocateRegistry;
46 import java.rmi.registry.Registry;
47 import java.util.Hashtable;
48 import java.util.Map;
49 import java.util.Properties;
50
51 import javax.naming.CommunicationException;
52 import javax.naming.Context;
53 import javax.naming.InvalidNameException;
54 import javax.naming.Name;
55 import javax.naming.NameAlreadyBoundException;
56 import javax.naming.NameNotFoundException;
57 import javax.naming.NameParser;
58 import javax.naming.NamingEnumeration;
59 import javax.naming.NamingException;
60 import javax.naming.OperationNotSupportedException;
61
62 /**
63  * The implementation of the RMI URL context. This context connects 
64  * 
65  * @author Audrius Meskauskas
66  */
67 public class ContextContinuation implements Context
68 {
69   /**
70    * The default registry location.
71    */
72   public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099";
73   
74   /**
75    * The local or remote RMI registry, performing the actual work for this
76    * context.
77    */
78   Registry registry;
79   
80  /**
81    * The properties.
82    */
83   Properties properties;
84   
85   /**
86    * The flag, indicating, that the lookup methods were called before.
87    * If the lookup methods were called before, the existing ORB cannot be
88    * destroyed, as references to the existing objects will become
89    * unfunctional.
90    */
91   boolean lookupCalled;
92   
93   /**
94    * Add new environment property to the environment of this context. Both name
95    * and value of the new property must not be null. If the property is already
96    * defined, is current value is replaced by the propVal. This method replaces
97    * the registry. The new registry will be lazily instantiated on the first
98    * call.
99    * 
100    * @param propName
101    *          the name of the new property
102    * @param propVal
103    *          the value of the new property
104    * @return the previous value of this property or null if the property has not
105    *         been previously defined
106    */
107   public Object addToEnvironment(String key, Object value)
108   {
109     removeRegistry();
110     if (key == null || value == null)
111       throw new NullPointerException();
112     return properties.put(key, value);
113   }
114
115   /**
116    * Returns the environment, associated with this naming context. The returned
117    * table should never be modified by the caller (the registry would not be updated
118    * in such case). Use {@link #addToEnvironment} and
119    * {@link #removeFromEnvironment} to modify the environement, if needed.
120    * 
121    * @return the table, representing the environment of this context
122    * @throws NamingException
123    */
124   public Hashtable getEnvironment() throws NamingException
125   {
126     return properties;
127   }
128
129   /**
130    * Removes the property with the given name from the environment. Returns
131    * without action if this property is not defined. Replaces the ORB,
132    * constructing the new ORB with the changes set of properties (you can
133    * replace the CORBA implementation provider, for instance). The new ORB will
134    * be lazily instantiated on the first call.
135    * 
136    * @param propName
137    *          the name of the property being removed.
138    * @return the value of the property that has been removed or null if the
139    *         property was not defined.
140    * @throws NamingException
141    */
142   public Object removeFromEnvironment(String propName) throws NamingException
143   {
144     removeRegistry();
145     return properties.remove(propName);
146   }
147   
148   /**
149    * Remove the current registry reference.
150    */
151   public void removeRegistry()
152   {
153     registry = null;    
154   }
155   
156   /**
157    * Get the cached or new registry reference.
158    * 
159    * @return the registry reference, either cached or new.
160    */
161   public Registry getRegistry() throws NamingException
162   {
163     if (registry == null)
164       {
165         String address = properties.getProperty(Context.PROVIDER_URL,
166                                                 DEFAULT_REGISTRY_LOCATION);
167         
168         // The format like rmi://localhost:1099 is expected. Parse.
169         if (!address.startsWith("rmi://"))
170           throw new InvalidNameException(address);
171         
172         String a = address.substring("rmi://".length());
173         
174         // The colon, if present, indicates the start of the port number.
175         int colon = a.lastIndexOf(':');
176         int port;
177         
178         try
179           {
180             if (colon >=0)
181               {
182                 port = Integer.parseInt(a.substring(colon+1));
183                 a = a.substring(0, colon);
184               }
185             else
186               port = Registry.REGISTRY_PORT;
187           }
188         catch (NumberFormatException e1)
189           {
190             throw new InvalidNameException(address);
191           } 
192             
193         try
194           {
195             registry = LocateRegistry.getRegistry(a, port);
196           }
197         catch (RemoteException e)
198           {
199             throw new CommunicationException(e.toString());
200           }
201       }
202     return registry;
203   }
204
205   /**
206    * Create the rmi url context that works, talking with the given RMI registry.
207    * 
208    * @param props
209    *          the properties for this context
210    * @param initialRegistry
211    *          the initial value of the registry
212    */
213   public ContextContinuation(Map props, Registry initialRegistry)
214   {
215     properties = new Properties();
216     if (props != null)
217       properties.putAll(props);
218     registry = initialRegistry;
219   }
220   
221   /**
222    * Bind the given name into this context. The .toString() is called to
223    * convert into the string representation, required by RMI registry.
224    * 
225    * @throws NamingException if the object is not an instance of Remote
226    */
227   public void bind(Name name, Object obj) throws NamingException
228   {
229     bind(name.toString(), obj);
230   }
231
232   /**
233    * Bind the given name into this context.
234    */
235   public void bind(String name, Object obj) throws NamingException
236   {
237     try
238       {
239         getRegistry().bind(name, (Remote) obj);
240       }
241     catch (AccessException e)
242       {
243         throw new NamingException("access:"+e.toString());
244       }
245     catch (RemoteException e)
246       {
247         throw new CommunicationException(e.toString());
248       }
249     catch (AlreadyBoundException e)
250       {
251         throw new NameAlreadyBoundException(name);
252       }
253     catch (ClassCastException c)
254       {
255         throw new NamingException("Only Remote can be bound:"
256                                   + obj.getClass().getName());
257       }
258   }
259
260   /**
261    * Not supported.
262    */
263   public Name composeName(Name name, Name prefix) throws NamingException
264   {
265     throw new OperationNotSupportedException();
266   }
267
268   /**
269    * Not supported.
270    */
271   public String composeName(String name, String prefix) throws NamingException
272   {
273     throw new OperationNotSupportedException();
274   }
275
276   /**
277    * Subcontexts are not supporte by RMI registry. The only supported case is an
278    * empty name (returns the cloned instance of self).
279    */
280   public Context createSubcontext(Name name) throws NamingException
281   {
282     if (name.size() == 0)
283       return new rmiURLContext(properties);
284     else
285       throw new OperationNotSupportedException();
286   }
287
288   /**
289    * Subcontexts are not supporte by RMI registry. The only supported case is an
290    * empty name (returns the cloned instance of self).
291    */
292   public Context createSubcontext(String name) throws NamingException
293   {
294     if (name.length() == 0)
295       return new rmiURLContext(properties);
296     else
297       throw new OperationNotSupportedException();
298   }
299
300   /**
301    * Subcontexts are not supporte by RMI registry.
302    */
303   public void destroySubcontext(Name name) throws NamingException
304   {
305     throw new OperationNotSupportedException();
306   }
307
308   /**
309    * Subcontexts are not supporte by RMI registry.
310    */
311   public void destroySubcontext(String name) throws NamingException
312   {
313     throw new OperationNotSupportedException();
314   }
315
316   /**
317    * Returns the naming service URL, same that was passed vie
318    * {@link Context#PROVIDER_URL}.
319    */
320   public String getNameInNamespace() throws NamingException
321   {
322     return properties.getProperty(Context.PROVIDER_URL,
323                                   DEFAULT_REGISTRY_LOCATION);
324   }
325
326   /**
327    * Not supported, this context never parses any names.
328    */
329   public NameParser getNameParser(Name name) throws NamingException
330   {
331     throw new OperationNotSupportedException();
332   }
333
334   /**
335    * Not supported, this context never parses any names.
336    */
337   public NameParser getNameParser(String name) throws NamingException
338   {
339     throw new OperationNotSupportedException();
340   }
341
342   /**
343    * List existing bindings of this context (the parameter must be empty name,
344    * indicating the root context). The class name of the returned name class
345    * pairs is "Remote", as this "quick preview" method should probably not call
346    * the naming service again. Use listBindings if more details are required.
347    */
348   public NamingEnumeration list(Name name) throws NamingException
349   {
350     if (name.size() > 0)
351       throw new OperationNotSupportedException("Only empty name is accepted");
352     return list("");
353   }
354
355   /**
356    * List existing bindings of this context (the parameter must be empty string,
357    * indicating the root context). The class name of the returned name class
358    * pairs is "Remote", as this "quick preview" method should probably not call
359    * the naming service again. Use listBindings if more details are required.
360    */
361   public NamingEnumeration list(String name) throws NamingException
362   {
363     if (name.length() > 0)
364       throw new OperationNotSupportedException("Only empty name is accepted");
365     
366     try
367       {
368         return new ListEnumeration(getRegistry().list());
369       }
370     catch (Exception e)
371       {
372         throw new NamingException(e.toString());
373       }
374   }
375
376   /**
377    * List existing bindings of this context (the parameter must be empty name,
378    * indicating the root context). 
379    */
380   public NamingEnumeration listBindings(Name name) throws NamingException
381   {
382     if (name.size() > 0)
383       throw new OperationNotSupportedException("Only empty name is accepted");
384     return listBindings("");
385   }
386
387   /**
388    * List existing bindings of this context (the parameter must be empty name,
389    * indicating the root context). 
390    */
391   public NamingEnumeration listBindings(String name) throws NamingException
392   {
393     if (name.length() > 0)
394       throw new OperationNotSupportedException("Only empty name is accepted");
395     
396     try
397       {
398         Registry r = getRegistry();
399         return new ListBindingsEnumeration(r.list(), r);
400       }
401     catch (Exception e)
402       {
403         throw new NamingException(e.toString());
404       }
405   }
406
407   /**
408    * Not supported.
409    */
410   public Object lookupLink(Name name) throws NamingException
411   {
412     throw new OperationNotSupportedException();
413   }
414
415   /**
416    * Not supported.
417    */
418   public Object lookupLink(String name) throws NamingException
419   {
420     throw new OperationNotSupportedException();
421   }
422
423   /**
424    * Rebinds this object.
425    * 
426    * @param name
427    *          the object name (.toString()) is used to convert into string
428    *          representation.
429    * @param the
430    *          object (must be an instance of Remote).
431    */
432   public void rebind(Name name, Object obj) throws NamingException
433   {
434     rebind(name.toString(), obj);
435   }
436
437   /**
438    * Rebinds this object.
439    * 
440    * @param name
441    *          the object name.
442    * @param the
443    *          object (must be an instance of Remote).
444    */
445   public void rebind(String name, Object obj) throws NamingException
446   {
447     try
448       {
449         getRegistry().rebind(name, (Remote) obj);
450       }
451     catch (AccessException e)
452       {
453         throw new NamingException("access:"+e.toString());
454       }
455     catch (RemoteException e)
456       {
457         throw new CommunicationException(e.toString());
458       }
459     catch (ClassCastException c)
460       {
461         throw new NamingException("Only Remote can be bound:"
462                                   + obj.getClass().getName());
463       }
464   }
465   
466   /**
467    * Renames the object. If the new name is already bound in the given context,
468    * the {@link AlreadyBoundException} is thrown and the oldName binding is
469    * preserved.
470    */
471   public void rename(Name oldName, Name newName) throws NamingException
472   {
473     rename(oldName.toString(), newName.toString());
474   }
475
476   /**
477    * Renames the object. If the new name is already bound in the given context,
478    * the {@link AlreadyBoundException} is thrown and the oldName binding is
479    * preserved.
480    */
481   public synchronized void rename(String oldName, String newName)
482       throws NamingException
483   {
484     try
485       {
486         Registry r = getRegistry();
487         Remote object = r.lookup(oldName);
488         r.unbind(oldName);
489         try
490           {
491             r.bind(newName, object);
492           }
493         catch (AlreadyBoundException e)
494           {
495             // Bind it back.
496             try
497               {
498                 r.bind(oldName, object);
499               }
500             catch (AlreadyBoundException e1)
501               {
502                 // We have just removed this name.
503                 throw new InternalError();
504               }
505             throw new NameAlreadyBoundException(newName);
506           }
507       }
508     catch (AccessException e)
509       {
510         throw new NamingException(e.toString());
511       }
512     catch (RemoteException e)
513       {
514         throw new CommunicationException(e.toString());
515       }
516     catch (NotBoundException e)
517       {
518         throw new CommunicationException(e.toString());
519       }
520   }
521
522   /**
523    * Unbind the object.
524    */
525   public void unbind(Name name) throws NamingException
526   {
527     unbind(name.toString());
528   }
529
530   /**
531    * Unbind the object.
532    */
533   public void unbind(String name) throws NamingException
534   {
535     try
536       {
537         getRegistry().unbind(name);
538       }
539     catch (AccessException e)
540       {
541         throw new NamingException(e.toString());
542       }
543     catch (RemoteException e)
544       {
545         throw new CommunicationException(e.toString());
546       }
547     catch (NotBoundException e)
548       {
549         throw new CommunicationException(e.toString());
550       }
551   }
552   
553   /**
554    * Release the associated resources.
555    */
556   public void close() throws NamingException
557   {
558     removeRegistry();
559   }
560   
561   /**
562    * Resolve the object by name.
563    * 
564    * @param name
565    *          the object name, .toString() is used to get the string
566    *          representation.
567    */
568   public Object lookup(Name name) throws NamingException
569   {
570     return lookup(name.toString());
571   }
572   
573   /**
574    * Resolve the object by name
575    * 
576    * @param name the object name.
577    */
578   public Object lookup(String name) throws NamingException
579   {
580     try
581       {
582         return getRegistry().lookup(name);
583       }
584     catch (AccessException e)
585       {
586         throw new NamingException(e.toString());
587       }
588     catch (RemoteException e)
589       {
590         throw new CommunicationException(e.toString());
591       }
592     catch (NotBoundException e)
593       {
594         throw new NameNotFoundException(name);
595       }
596   }
597 }