View Javadoc

1   /*
2    * Copyright (C) The Apache Software Foundation. All rights reserved.
3    *
4    * This software is published under the terms of the Apache Software License
5    * version 1.1, a copy of which has been included with this distribution in
6    * the LICENSE file.
7    */
8   package org.apache.avalon.excalibur.naming;
9   
10  import java.util.Hashtable;
11  import javax.naming.Context;
12  import javax.naming.InvalidNameException;
13  import javax.naming.NamingEnumeration;
14  import javax.naming.Name;
15  import javax.naming.NameParser;
16  import javax.naming.ContextNotEmptyException;
17  import javax.naming.NameAlreadyBoundException;
18  import javax.naming.NamingException;
19  import javax.naming.NotContextException;
20  import javax.naming.Reference;
21  import javax.naming.Referenceable;
22  import javax.naming.OperationNotSupportedException;
23  
24  /***
25   * Abstract local JNDI Context that can be inherited from to
26   * provide a particular type of Context. These contexts are assumed to be
27   * on the same machine.
28   *
29   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
30   * @version $Revision: 1.2 $
31   */
32  public abstract class AbstractLocalContext
33      extends AbstractContext
34  {
35      protected Context    m_parent;
36      protected Namespace  m_namespace;
37  
38      public AbstractLocalContext( final Namespace namespace,
39                                   final Hashtable environment,
40                                   final Context parent )
41      {
42          super( environment );
43          m_namespace = namespace;
44          m_parent = parent;
45      }
46  
47      protected boolean isDestroyableContext( final Object object )
48          throws NamingException
49      {
50          return getClass().isInstance( object );
51      }
52  
53      protected abstract Context newContext()
54          throws NamingException;
55  
56      protected abstract Context cloneContext()
57          throws NamingException;
58  
59      /***
60       * Helper method to bind
61       */
62      protected void bind( final Name name, Object object, final boolean rebind )
63          throws NamingException
64      {
65          if( isSelf( name ) )
66          {
67              throw new InvalidNameException( "Failed to bind self" );
68          }
69  
70          if( 1 == name.size() )
71          {
72              boolean alreadyBound = false;
73              try
74              {
75                  localLookup( name );
76                  alreadyBound = true;
77              }
78              catch( final NamingException ne ) {}
79  
80              if( !rebind && alreadyBound )
81              {
82                  throw new NameAlreadyBoundException( name.get( 0 ) );
83              }
84              else
85              {
86                  //Should this occur here or in the factories ???
87                  if( object instanceof Referenceable )
88                  {
89                      object = ((Referenceable)object).getReference();
90                  }
91  
92                  // Call getStateToBind for using any state factories
93                  final Name atom = name.getPrefix( 1 );
94                  object = m_namespace.getStateToBind( object, atom, this, m_environment );
95  
96                  doLocalBind( name, object );
97              }
98          }
99          else
100         {
101             final Context context = lookupSubContext( getPathName( name ) );
102             if( rebind )
103             {
104                 context.rebind( getLeafName( name ), object );
105             }
106             else
107             {
108                 context.bind( getLeafName( name ), object );
109             }
110         }
111     }
112 
113     protected abstract void doLocalBind( Name name, Object object )
114         throws NamingException;
115 
116     public void close()
117     {
118         m_parent = null;
119         m_namespace = null;
120     }
121 
122     /***
123      * Create a Subcontext.
124      *
125      * @param name the name of subcontext
126      * @return the created context
127      * @exception NamingException if an error occurs (ie context exists, badly formated name etc)
128      */
129     public Context createSubcontext( final Name name )
130         throws NamingException
131     {
132         final Context context = newContext();
133         bind( name, context );
134         return context;
135     }
136 
137     public void destroySubcontext( final Name name )
138         throws NamingException
139     {
140         if( isSelf( name ) )
141         {
142             throw new InvalidNameException( "Failed to destroy self" );
143         }
144 
145         if( 1 == name.size() )
146         {
147             Object object = null;
148             try
149             {
150                 object = localLookup( name );
151             }
152             catch( final NamingException ne )
153             {
154                 return;
155             }
156 
157             checkUnbindContext( name, object );
158 
159             doLocalUnbind( name );
160         }
161         else
162         {
163             final Context context = lookupSubContext( getPathName( name ) );
164 
165             Object object = null;
166 
167             final Name atom = getLeafName( name );
168             try
169             {
170                 object = context.lookup( atom );
171             }
172             catch( final NamingException ne )
173             {
174                 return;
175             }
176 
177             checkUnbindContext( atom, object );
178 
179             context.destroySubcontext( atom );
180         }
181     }
182 
183     protected void checkUnbindContext( final Name name, final Object entry )
184         throws NamingException
185     {
186         if( !isDestroyableContext( entry ) )
187         {
188             throw new NotContextException( name.toString() );
189         }
190 
191         final Context context = (Context)entry;
192         if( context.list( "" ).hasMoreElements() )
193         {
194             throw new ContextNotEmptyException( name.toString() );
195         }
196     }
197 
198     public String getNameInNamespace()
199         throws NamingException
200     {
201         throw new OperationNotSupportedException( "Namespace has no notion of a 'full name'" );
202     }
203 
204     protected NameParser getNameParser()
205         throws NamingException
206     {
207         return m_namespace.getNameParser();
208     }
209 
210     /***
211      * Enumerates the names bound in the named context.
212      *
213      * @param name the name of the context
214      * @return the enumeration
215      * @exception NamingException if an error occurs
216      */
217     public NamingEnumeration list( final Name name )
218         throws NamingException
219     {
220         if( isSelf( name ) )
221         {
222             return doLocalList();
223         }
224         else
225         {
226             // Perhaps 'name' names a context
227             final Context context = lookupSubContext( name );
228             return context.list( "" );
229         }
230     }
231 
232     protected abstract NamingEnumeration doLocalList()
233         throws NamingException;
234 
235     protected abstract NamingEnumeration doLocalListBindings()
236         throws NamingException;
237 
238     /***
239      * Enumerates the names bound in the named context, along with the objects bound to them.
240      *
241      * @param name the name of the context
242      * @return the enumeration
243      * @exception NamingException if an error occurs
244      */
245     public NamingEnumeration listBindings( final Name name )
246         throws NamingException
247     {
248         if( isSelf( name ) )
249         {
250             return doLocalListBindings();
251         }
252         else
253         {
254             // Perhaps 'name' names a context
255             final Context context = lookupSubContext( name );
256             return context.listBindings( "" );
257         }
258     }
259 
260     /***
261      * Get the object named.
262      *
263      * @param name the name
264      * @return the object
265      * @exception NamingException if an error occurs (ie object name is inavlid or unbound)
266      */
267     public Object lookup( final Name name )
268         throws NamingException
269     {
270         //if it refers to base context return a copy of it.
271         if( isSelf( name ) )
272         {
273             return cloneContext();
274         }
275 
276         if( 1 == name.size() )
277         {
278             return localLookup( name );
279         }
280         else
281         {
282             final Context context = lookupSubContext( getPathName( name ) );
283             return context.lookup( getLeafName( name ) );
284         }
285     }
286 
287     /***
288      * Lookup entry in local context.
289      *
290      * @param name the name in local context (size() == 1)
291      * @return the bound object
292      * @exception NamingException if an error occurs
293      */
294     protected Object localLookup( final Name name )
295         throws NamingException
296     {
297         final Object value = doLocalLookup( name );
298 
299         // Call getObjectInstance for using any object factories
300         try
301         {
302             final Name atom = name.getPrefix( 1 );
303             return m_namespace.getObjectInstance( value, atom, this, m_environment );
304         }
305         catch( final Exception e )
306         {
307             final NamingException ne = new NamingException( "getObjectInstance failed" );
308             ne.setRootCause( e );
309             throw ne;
310         }
311     }
312 
313     /***
314      * Actually lookup raw entry in local context.
315      * When overidding this it is not neccesary to resolve references etc.
316      *
317      * @param name the name in local context (size() == 1)
318      * @return the bound object
319      * @exception NamingException if an error occurs
320      */
321     protected abstract Object doLocalLookup( Name name )
322         throws NamingException;
323 
324     /***
325      * Lookup a sub-context of current context.
326      * Note that name must have 1 or more elements.
327      *
328      * @param name the name of subcontext
329      * @return the sub-Context
330      * @exception NamingException if an error occurs (like named entry is not a Context)
331      */
332     protected Context lookupSubContext( final Name name )
333         throws NamingException
334     {
335         final Name atom = name.getPrefix( 1 );
336         Object object = localLookup( atom );
337 
338         if( 1 != name.size() )
339         {
340             if( !(object instanceof Context) )
341             {
342                 throw new NotContextException( atom.toString() );
343             }
344 
345             object = ((Context)object).lookup( name.getSuffix( 1 ) );
346         }
347 
348         if( !(object instanceof Context) )
349         {
350             throw new NotContextException( name.toString() );
351         }
352 
353         //((Context)object).close();
354         return (Context)object;
355     }
356 
357     /***
358      * Unbind a object from a name.
359      *
360      * @param name the name
361      * @exception NamingException if an error occurs
362      */
363     public void unbind( final Name name )
364         throws NamingException
365     {
366         if( isSelf( name ) )
367         {
368             throw new InvalidNameException( "Cannot unbind self" );
369         }
370         else if( 1 == name.size() )
371         {
372             doLocalUnbind( name );
373         }
374         else
375         {
376             final Context context = lookupSubContext( getPathName ( name ) );
377             context.unbind( getLeafName( name ) );
378         }
379     }
380 
381     /***
382      * Actually unbind raw entry in local context.
383      *
384      * @param name the name in local context (size() == 1)
385      * @exception NamingException if an error occurs
386      */
387     protected abstract void doLocalUnbind( Name name )
388         throws NamingException;
389 }