View Javadoc

1   /*
2    * Copyright 2005-2008 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ldap.pool;
18  
19  import java.util.Hashtable;
20  
21  import javax.naming.Context;
22  import javax.naming.Name;
23  import javax.naming.NameParser;
24  import javax.naming.NamingEnumeration;
25  import javax.naming.NamingException;
26  
27  import org.apache.commons.lang.Validate;
28  import org.apache.commons.pool.KeyedObjectPool;
29  import org.springframework.ldap.pool.factory.PoolingContextSource;
30  
31  /**
32   * Used by {@link PoolingContextSource} to wrap a {@link Context}, delegating most methods
33   * to the underlying context, retains a reference to the pool the context was checked out
34   * from and returns itself to the pool when {@link #close()} is called.
35   * 
36   * @author Eric Dalquist
37   */
38  public class DelegatingContext implements Context {
39      private KeyedObjectPool keyedObjectPool;
40      private Context delegateContext;
41      private final DirContextType dirContextType;
42      
43  
44      /**
45       * Create a new delegating context for the specified pool, context and context type.
46       * 
47       * @param keyedObjectPool The pool the delegate context was checked out from.
48       * @param delegateContext The context to delegate operations to.
49       * @param dirContextType The type of context, used as a key for the pool.
50       * @throws IllegalArgumentException if any of the arguments are null
51       */
52      public DelegatingContext(KeyedObjectPool keyedObjectPool, Context delegateContext, DirContextType dirContextType) {
53          Validate.notNull(keyedObjectPool, "keyedObjectPool may not be null");
54          Validate.notNull(delegateContext, "delegateContext may not be null");
55          Validate.notNull(dirContextType, "dirContextType may not be null");
56          
57          this.keyedObjectPool = keyedObjectPool;
58          this.delegateContext = delegateContext;
59          this.dirContextType = dirContextType;
60      }
61      
62      
63      //***** Helper Methods *****//
64      
65      /**
66       * @return The direct delegate for this context proxy
67       */
68      public Context getDelegateContext() {
69          return this.delegateContext;
70      }
71      
72      /**
73       * Recursivley inspect delegates until a non-delegating context is found.
74       * 
75       * @return The innermost (real) Context that is being delegated to.
76       */
77      public Context getInnermostDelegateContext() {
78          final Context delegateContext = this.getDelegateContext();
79          
80          if (delegateContext instanceof DelegatingContext) {
81              return ((DelegatingContext)delegateContext).getInnermostDelegateContext();
82          }
83  
84          return delegateContext;
85      }
86      
87      /**
88       * @throws NamingException If the delegate is null, {@link #close()} has been called.
89       */
90      protected void assertOpen() throws NamingException {
91          if (this.delegateContext == null) {
92              throw new NamingException("Context is closed.");
93          }
94      }
95  
96      
97      //***** Object methods *****//
98  
99      /**
100      * @see java.lang.Object#equals(java.lang.Object)
101      */
102     public boolean equals(Object obj) {
103         if (this == obj) {
104             return true;
105         }
106         if (!(obj instanceof Context)) {
107             return false;
108         }
109         
110         final Context thisContext = this.getInnermostDelegateContext();
111         Context otherContext = (Context)obj;
112         if (otherContext instanceof DelegatingContext) {
113             otherContext = ((DelegatingContext)otherContext).getInnermostDelegateContext();
114         }
115         
116         return thisContext == otherContext || (thisContext != null && thisContext.equals(otherContext));
117     }
118 
119     /**
120      * @see java.lang.Object#hashCode()
121      */
122     public int hashCode() {
123         final Context context = this.getInnermostDelegateContext();
124         return (context != null ? context.hashCode() : 0);
125     }
126 
127     /**
128      * @see java.lang.Object#toString()
129      */
130     public String toString() {
131         final Context context = this.getInnermostDelegateContext();
132         return (context != null ? context.toString() : "Context is closed");
133     }
134     
135     
136     //***** Context Interface Delegates *****//
137 
138     /**
139      * @see javax.naming.Context#addToEnvironment(java.lang.String, java.lang.Object)
140      */
141     public Object addToEnvironment(String propName, Object propVal) throws NamingException {
142         throw new UnsupportedOperationException("Cannot call addToEnvironment on a pooled context");
143     }
144 
145     /**
146      * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object)
147      */
148     public void bind(Name name, Object obj) throws NamingException {
149         this.assertOpen();
150         this.getDelegateContext().bind(name, obj);
151     }
152 
153     /**
154      * @see javax.naming.Context#bind(java.lang.String, java.lang.Object)
155      */
156     public void bind(String name, Object obj) throws NamingException {
157         this.assertOpen();
158         this.getDelegateContext().bind(name, obj);
159     }
160 
161     /**
162      * @see javax.naming.Context#close()
163      */
164     public void close() throws NamingException {
165         final Context context = this.getInnermostDelegateContext();
166         if (context == null) {
167             return;
168         }
169         
170         //Get a local reference so the member can be nulled earlier
171         this.delegateContext = null;
172 
173         //Return the object to the Pool and then null the pool reference
174         try {
175             this.keyedObjectPool.returnObject(this.dirContextType, context);
176         }
177         catch (Exception e) {
178             final NamingException namingException = new NamingException("Failed to return delegate Context to pool.");
179             namingException.setRootCause(e);
180             throw namingException;
181         }
182         finally {
183             this.keyedObjectPool = null;
184         }
185     }
186 
187     /**
188      * @see javax.naming.Context#composeName(javax.naming.Name, javax.naming.Name)
189      */
190     public Name composeName(Name name, Name prefix) throws NamingException {
191         this.assertOpen();
192         return this.getDelegateContext().composeName(name, prefix);
193     }
194 
195     /**
196      * @see javax.naming.Context#composeName(java.lang.String, java.lang.String)
197      */
198     public String composeName(String name, String prefix) throws NamingException {
199         this.assertOpen();
200         return this.getDelegateContext().composeName(name, prefix);
201     }
202 
203     /**
204      * @see javax.naming.Context#createSubcontext(javax.naming.Name)
205      */
206     public Context createSubcontext(Name name) throws NamingException {
207         throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
208     }
209 
210     /**
211      * @see javax.naming.Context#createSubcontext(java.lang.String)
212      */
213     public Context createSubcontext(String name) throws NamingException {
214         throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
215     }
216 
217     /**
218      * @see javax.naming.Context#destroySubcontext(javax.naming.Name)
219      */
220     public void destroySubcontext(Name name) throws NamingException {
221         throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
222     }
223 
224     /**
225      * @see javax.naming.Context#destroySubcontext(java.lang.String)
226      */
227     public void destroySubcontext(String name) throws NamingException {
228         throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
229     }
230 
231     /**
232      * @see javax.naming.Context#getEnvironment()
233      */
234     public Hashtable getEnvironment() throws NamingException {
235         this.assertOpen();
236         return this.getDelegateContext().getEnvironment();
237     }
238 
239     /**
240      * @see javax.naming.Context#getNameInNamespace()
241      */
242     public String getNameInNamespace() throws NamingException {
243         this.assertOpen();
244         return this.getDelegateContext().getNameInNamespace();
245     }
246 
247     /**
248      * @see javax.naming.Context#getNameParser(javax.naming.Name)
249      */
250     public NameParser getNameParser(Name name) throws NamingException {
251         this.assertOpen();
252         return this.getDelegateContext().getNameParser(name);
253     }
254 
255     /**
256      * @see javax.naming.Context#getNameParser(java.lang.String)
257      */
258     public NameParser getNameParser(String name) throws NamingException {
259         this.assertOpen();
260         return this.getDelegateContext().getNameParser(name);
261     }
262 
263     /**
264      * @see javax.naming.Context#list(javax.naming.Name)
265      */
266     public NamingEnumeration list(Name name) throws NamingException {
267         this.assertOpen();
268         return this.getDelegateContext().list(name);
269     }
270 
271     /**
272      * @see javax.naming.Context#list(java.lang.String)
273      */
274     public NamingEnumeration list(String name) throws NamingException {
275         this.assertOpen();
276         return this.getDelegateContext().list(name);
277     }
278 
279     /**
280      * @see javax.naming.Context#listBindings(javax.naming.Name)
281      */
282     public NamingEnumeration listBindings(Name name) throws NamingException {
283         this.assertOpen();
284         return this.getDelegateContext().listBindings(name);
285     }
286 
287     /**
288      * @see javax.naming.Context#listBindings(java.lang.String)
289      */
290     public NamingEnumeration listBindings(String name) throws NamingException {
291         this.assertOpen();
292         return this.getDelegateContext().listBindings(name);
293     }
294 
295     /**
296      * @see javax.naming.Context#lookup(javax.naming.Name)
297      */
298     public Object lookup(Name name) throws NamingException {
299         this.assertOpen();
300         return this.getDelegateContext().lookup(name);
301     }
302 
303     /**
304      * @see javax.naming.Context#lookup(java.lang.String)
305      */
306     public Object lookup(String name) throws NamingException {
307         this.assertOpen();
308         return this.getDelegateContext().lookup(name);
309     }
310 
311     /**
312      * @see javax.naming.Context#lookupLink(javax.naming.Name)
313      */
314     public Object lookupLink(Name name) throws NamingException {
315         this.assertOpen();
316         return this.getDelegateContext().lookupLink(name);
317     }
318 
319     /**
320      * @see javax.naming.Context#lookupLink(java.lang.String)
321      */
322     public Object lookupLink(String name) throws NamingException {
323         this.assertOpen();
324         return this.getDelegateContext().lookupLink(name);
325     }
326 
327     /**
328      * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object)
329      */
330     public void rebind(Name name, Object obj) throws NamingException {
331         this.assertOpen();
332         this.getDelegateContext().rebind(name, obj);
333     }
334 
335     /**
336      * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object)
337      */
338     public void rebind(String name, Object obj) throws NamingException {
339         this.assertOpen();
340         this.getDelegateContext().rebind(name, obj);
341     }
342 
343     /**
344      * @see javax.naming.Context#removeFromEnvironment(java.lang.String)
345      */
346     public Object removeFromEnvironment(String propName) throws NamingException {
347         throw new UnsupportedOperationException("Cannot call removeFromEnvironment on a pooled context");
348     }
349 
350     /**
351      * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name)
352      */
353     public void rename(Name oldName, Name newName) throws NamingException {
354         this.assertOpen();
355         this.getDelegateContext().rename(oldName, newName);
356     }
357 
358     /**
359      * @see javax.naming.Context#rename(java.lang.String, java.lang.String)
360      */
361     public void rename(String oldName, String newName) throws NamingException {
362         this.assertOpen();
363         this.getDelegateContext().rename(oldName, newName);
364     }
365 
366     /**
367      * @see javax.naming.Context#unbind(javax.naming.Name)
368      */
369     public void unbind(Name name) throws NamingException {
370         this.assertOpen();
371         this.getDelegateContext().unbind(name);
372     }
373 
374     /**
375      * @see javax.naming.Context#unbind(java.lang.String)
376      */
377     public void unbind(String name) throws NamingException {
378         this.assertOpen();
379         this.getDelegateContext().unbind(name);
380     }
381 }