1 /*
2 * Copyright 1999-2004 The Apache Software Foundation
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.apache.naming.core;
18
19 import java.util.Hashtable;
20
21 import javax.naming.CompositeName;
22 import javax.naming.Context;
23 import javax.naming.Name;
24 import javax.naming.NameParser;
25 import javax.naming.NamingEnumeration;
26 import javax.naming.NamingException;
27 import javax.naming.NotContextException;
28 import javax.naming.OperationNotSupportedException;
29 import javax.naming.directory.SearchControls;
30
31 // Based on a merge of various catalina naming contexts
32 // Name is used - it provide better oportunities for reuse and optimizations
33
34 /**
35 * Base Context implementation. Use it if the source doesn't support attributes.
36 *
37 * Implements all JNDI methods with reasonable defaults or UnsuportedOperation.
38 *
39 * IMPORTANT: all contexts should use setters/getters for configuration, instead
40 * of the Hashtable. The default constructor will use introspection to configure
41 * and may provide ( via a hook ? ) JMX management on all contexts.
42 *
43 * All methods use Name variant. They should expect an arbitrary implementation, but
44 * it's recommended to check if ServerName is used - and take advantage of the
45 * specific features ( MessageBytes, etc ).
46 *
47 * @author Remy Maucherat
48 * @author Costin Manolache
49 */
50 public class BaseContext extends BaseNaming implements Context {
51
52 public BaseContext() {
53 super();
54 }
55
56 public BaseContext(Hashtable env) {
57 super(env);
58 }
59
60
61 // -------------------- Context impl --------------------
62
63 /**
64 * Retrieves the named object. If name is empty, returns a new instance
65 * of this context (which represents the same naming context as this
66 * context, but its environment may be modified independently and it may
67 * be accessed concurrently).
68 *
69 * @param name the name of the object to look up
70 * @return the object bound to name
71 * @exception javax.naming.NamingException if a naming exception is encountered
72 */
73 public Object lookup(Name name)
74 throws NamingException {
75 return lookup(name, true);
76 }
77
78 /**
79 * Retrieves the named object.
80 *
81 * @param name the name of the object to look up
82 * @return the object bound to name
83 * @exception javax.naming.NamingException if a naming exception is encountered
84 */
85 public Object lookup(String name)
86 throws NamingException {
87 return lookup(string2Name(name), true);
88 }
89
90
91 /**
92 * Binds a name to an object. All intermediate contexts and the target
93 * context (that named by all but terminal atomic component of the name)
94 * must already exist.
95 *
96 * @param name the name to bind; may not be empty
97 * @param obj the object to bind; possibly null
98 * @exception javax.naming.NameAlreadyBoundException if name is already bound
99 * @exception javax.naming.NamingException if a naming exception is encountered
100 */
101 public void bind(Name name, Object obj)
102 throws NamingException {
103 bind(name, obj, null, false);
104 }
105
106
107 /**
108 * Binds a name to an object.
109 *
110 * @param name the name to bind; may not be empty
111 * @param obj the object to bind; possibly null
112 * @exception javax.naming.NameAlreadyBoundException if name is already bound
113 * @exception javax.naming.NamingException if a naming exception is encountered
114 */
115 public void bind(String name, Object obj)
116 throws NamingException {
117 bind(string2Name(name), obj, null, false);
118 }
119
120
121 /**
122 * Binds a name to an object, overwriting any existing binding. All
123 * intermediate contexts and the target context (that named by all but
124 * terminal atomic component of the name) must already exist.
125 * <p>
126 * If the object is a DirContext, any existing attributes associated with
127 * the name are replaced with those of the object. Otherwise, any
128 * existing attributes associated with the name remain unchanged.
129 *
130 * @param name the name to bind; may not be empty
131 * @param obj the object to bind; possibly null
132 * @exception javax.naming.NamingException if a naming exception is encountered
133 */
134 public void rebind(Name name, Object obj)
135 throws NamingException {
136 bind(name, obj, null, true);
137 }
138
139
140 /**
141 * Binds a name to an object, overwriting any existing binding.
142 *
143 * @param name the name to bind; may not be empty
144 * @param obj the object to bind; possibly null
145 * @exception javax.naming.NamingException if a naming exception is encountered
146 */
147 public void rebind(String name, Object obj)
148 throws NamingException {
149 bind(string2Name(name), obj, null, true);
150 }
151
152
153 /**
154 * Unbinds the named object. Removes the terminal atomic name in name
155 * from the target context--that named by all but the terminal atomic
156 * part of name.
157 * <p>
158 * This method is idempotent. It succeeds even if the terminal atomic
159 * name is not bound in the target context, but throws
160 * NameNotFoundException if any of the intermediate contexts do not exist.
161 *
162 * @param name the name to bind; may not be empty
163 * @exception javax.naming.NameNotFoundException if an intermediate context does not
164 * exist
165 * @exception javax.naming.NamingException if a naming exception is encountered
166 */
167 public void unbind(Name name)
168 throws NamingException {
169 unbind(name, false);
170 }
171
172 public void unbind(String name)
173 throws NamingException {
174 unbind(string2Name(name), false);
175 }
176
177
178 /**
179 * Binds a new name to the object bound to an old name, and unbinds the
180 * old name. Both names are relative to this context. Any attributes
181 * associated with the old name become associated with the new name.
182 * Intermediate contexts of the old name are not changed.
183 *
184 * @param oldName the name of the existing binding; may not be empty
185 * @param newName the name of the new binding; may not be empty
186 * @exception javax.naming.NameAlreadyBoundException if newName is already bound
187 * @exception javax.naming.NamingException if a naming exception is encountered
188 */
189 public void rename(String oldName, String newName)
190 throws NamingException {
191 rename(string2Name(oldName), string2Name(newName));
192 }
193
194
195 /**
196 * Enumerates the names bound in the named context, along with the class
197 * names of objects bound to them. The contents of any subcontexts are
198 * not included.
199 * <p>
200 * If a binding is added to or removed from this context, its effect on
201 * an enumeration previously returned is undefined.
202 *
203 * @param name the name of the context to list
204 * @return an enumeration of the names and class names of the bindings in
205 * this context. Each element of the enumeration is of type NameClassPair.
206 * @exception javax.naming.NamingException if a naming exception is encountered
207 */
208 public NamingEnumeration list(String name)
209 throws NamingException {
210 return list(string2Name(name));
211 }
212
213 public NamingEnumeration list(Name name)
214 throws NamingException {
215 return new NamingContextEnumeration(getChildren(), this, false);
216 }
217
218
219 /**
220 * Enumerates the names bound in the named context, along with the
221 * objects bound to them. The contents of any subcontexts are not
222 * included.
223 * <p>
224 * If a binding is added to or removed from this context, its effect on
225 * an enumeration previously returned is undefined.
226 *
227 * @param name the name of the context to list
228 * @return an enumeration of the bindings in this context.
229 * Each element of the enumeration is of type Binding.
230 * @exception javax.naming.NamingException if a naming exception is encountered
231 */
232 public NamingEnumeration listBindings(Name name)
233 throws NamingException {
234 return new NamingContextEnumeration(getChildren(), this, true);
235 }
236
237 public NamingEnumeration listBindings(String name)
238 throws NamingException {
239 return listBindings(string2Name(name));
240 }
241
242
243 /**
244 * Destroys the named context and removes it from the namespace. Any
245 * attributes associated with the name are also removed. Intermediate
246 * contexts are not destroyed.
247 * <p>
248 * This method is idempotent. It succeeds even if the terminal atomic
249 * name is not bound in the target context, but throws
250 * NameNotFoundException if any of the intermediate contexts do not exist.
251 *
252 * In a federated naming system, a context from one naming system may be
253 * bound to a name in another. One can subsequently look up and perform
254 * operations on the foreign context using a composite name. However, an
255 * attempt destroy the context using this composite name will fail with
256 * NotContextException, because the foreign context is not a "subcontext"
257 * of the context in which it is bound. Instead, use unbind() to remove
258 * the binding of the foreign context. Destroying the foreign context
259 * requires that the destroySubcontext() be performed on a context from
260 * the foreign context's "native" naming system.
261 *
262 * @param name the name of the context to be destroyed; may not be empty
263 * @exception javax.naming.NameNotFoundException if an intermediate context does not
264 * exist
265 * @exception javax.naming.NotContextException if the name is bound but does not name
266 * a context, or does not name a context of the appropriate type
267 */
268 public void destroySubcontext(Name name)
269 throws NamingException {
270 unbind(name, true);
271 }
272
273
274 /**
275 * Destroys the named context and removes it from the namespace.
276 *
277 * @param name the name of the context to be destroyed; may not be empty
278 * @exception javax.naming.NameNotFoundException if an intermediate context does not
279 * exist
280 * @exception javax.naming.NotContextException if the name is bound but does not name
281 * a context, or does not name a context of the appropriate type
282 */
283 public void destroySubcontext(String name)
284 throws NamingException {
285 unbind(string2Name(name), true);
286 }
287
288
289 /**
290 * Creates and binds a new context. Creates a new context with the given
291 * name and binds it in the target context (that named by all but
292 * terminal atomic component of the name). All intermediate contexts and
293 * the target context must already exist.
294 *
295 * @param name the name of the context to create; may not be empty
296 * @return the newly created context
297 * @exception javax.naming.NameAlreadyBoundException if name is already bound
298 * @exception javax.naming.NamingException if a naming exception is encountered
299 */
300 public Context createSubcontext(Name name)
301 throws NamingException {
302 return createSubcontext(name, null);
303 }
304
305 public Context createSubcontext(String name)
306 throws NamingException {
307 return createSubcontext(string2Name(name), null);
308 }
309
310 public void rename(Name oldName, Name newName)
311 throws NamingException
312 {
313 // Override if needed
314 Object value = lookup(oldName, false);
315 bind(newName, value, null, false);
316 unbind(oldName, true);
317
318 }
319
320 /**
321 * Retrieves the named object, following links except for the terminal
322 * atomic component of the name. If the object bound to name is not a
323 * link, returns the object itself.
324 *
325 * @param name the name of the object to look up
326 * @return the object bound to name, not following the terminal link
327 * (if any).
328 * @exception javax.naming.NamingException if a naming exception is encountered
329 */
330 public Object lookupLink(Name name)
331 throws NamingException {
332 return lookup(name, false);
333 }
334
335
336 /**
337 * Retrieves the named object, following links except for the terminal
338 * atomic component of the name.
339 *
340 * @param name the name of the object to look up
341 * @return the object bound to name, not following the terminal link
342 * (if any).
343 * @exception javax.naming.NamingException if a naming exception is encountered
344 */
345 public Object lookupLink(String name)
346 throws NamingException {
347 return lookupLink(string2Name(name));
348 }
349
350
351 /**
352 * Retrieves the parser associated with the named context. In a
353 * federation of namespaces, different naming systems will parse names
354 * differently. This method allows an application to get a parser for
355 * parsing names into their atomic components using the naming convention
356 * of a particular naming system. Within any single naming system,
357 * NameParser objects returned by this method must be equal (using the
358 * equals() test).
359 *
360 * @param name the name of the context from which to get the parser
361 * @return a name parser that can parse compound names into their atomic
362 * components
363 * @exception javax.naming.NamingException if a naming exception is encountered
364 */
365 public NameParser getNameParser(Name name)
366 throws NamingException {
367
368 while ((!name.isEmpty()) && (name.get(0).length() == 0))
369 name = name.getSuffix(1);
370 if (name.isEmpty())
371 return nameParser;
372
373 if (name.size() > 1) {
374 Object obj = lookup(name.get(0));
375 if (obj instanceof Context) {
376 return ((Context) obj).getNameParser(name.getSuffix(1));
377 } else {
378 throw new NotContextException(name.toString());
379 }
380 }
381
382 return nameParser;
383
384 }
385
386
387 /**
388 * Retrieves the parser associated with the named context.
389 *
390 * @param name the name of the context from which to get the parser
391 * @return a name parser that can parse compound names into their atomic
392 * components
393 * @exception javax.naming.NamingException if a naming exception is encountered
394 */
395 public NameParser getNameParser(String name)
396 throws NamingException {
397 return getNameParser(new CompositeName(name));
398 }
399
400 /**
401 * Composes the name of this context with a name relative to this context.
402 * <p>
403 * Given a name (name) relative to this context, and the name (prefix)
404 * of this context relative to one of its ancestors, this method returns
405 * the composition of the two names using the syntax appropriate for the
406 * naming system(s) involved. That is, if name names an object relative
407 * to this context, the result is the name of the same object, but
408 * relative to the ancestor context. None of the names may be null.
409 *
410 * @param name a name relative to this context
411 * @param prefix the name of this context relative to one of its ancestors
412 * @return the composition of prefix and name
413 * @exception javax.naming.NamingException if a naming exception is encountered
414 */
415 public Name composeName(Name name, Name prefix)
416 throws NamingException {
417 prefix = (Name) prefix.clone();
418 return prefix.addAll(name);
419 }
420
421
422 /**
423 * Composes the name of this context with a name relative to this context.
424 *
425 * @param name a name relative to this context
426 * @param prefix the name of this context relative to one of its ancestors
427 * @return the composition of prefix and name
428 * @exception javax.naming.NamingException if a naming exception is encountered
429 */
430 public String composeName(String name, String prefix)
431 throws NamingException {
432 return prefix + "/" + name;
433 }
434
435
436 /**
437 * Adds a new environment property to the environment of this context. If
438 * the property already exists, its value is overwritten.
439 *
440 * @param propName the name of the environment property to add; may not
441 * be null
442 * @param propVal the value of the property to add; may not be null
443 * @exception javax.naming.NamingException if a naming exception is encountered
444 */
445 public Object addToEnvironment(String propName, Object propVal)
446 throws NamingException {
447 return env.put(propName, propVal);
448 }
449
450
451 /**
452 * Removes an environment property from the environment of this context.
453 *
454 * @param propName the name of the environment property to remove;
455 * may not be null
456 * @exception javax.naming.NamingException if a naming exception is encountered
457 */
458 public Object removeFromEnvironment(String propName)
459 throws NamingException {
460 return env.remove(propName);
461 }
462
463
464 /**
465 * Retrieves the environment in effect for this context. See class
466 * description for more details on environment properties.
467 * The caller should not make any changes to the object returned: their
468 * effect on the context is undefined. The environment of this context
469 * may be changed using addToEnvironment() and removeFromEnvironment().
470 *
471 * @return the environment of this context; never null
472 * @exception javax.naming.NamingException if a naming exception is encountered
473 */
474 public Hashtable getEnvironment()
475 throws NamingException {
476 return env;
477 }
478
479
480 /**
481 * Closes this context. This method releases this context's resources
482 * immediately, instead of waiting for them to be released automatically
483 * by the garbage collector.
484 * This method is idempotent: invoking it on a context that has already
485 * been closed has no effect. Invoking any other method on a closed
486 * context is not allowed, and results in undefined behaviour.
487 *
488 * @exception javax.naming.NamingException if a naming exception is encountered
489 */
490 public void close()
491 throws NamingException {
492 // We don't own the env., but the clone
493 env.clear();
494 }
495
496
497 /**
498 * Retrieves the full name of this context within its own namespace.
499 * <p>
500 * Many naming services have a notion of a "full name" for objects in
501 * their respective namespaces. For example, an LDAP entry has a
502 * distinguished name, and a DNS record has a fully qualified name. This
503 * method allows the client application to retrieve this name. The string
504 * returned by this method is not a JNDI composite name and should not be
505 * passed directly to context methods. In naming systems for which the
506 * notion of full name does not make sense,
507 * OperationNotSupportedException is thrown.
508 *
509 * @return this context's name in its own namespace; never null
510 * @exception javax.naming.OperationNotSupportedException if the naming system does
511 * not have the notion of a full name
512 * @exception javax.naming.NamingException if a naming exception is encountered
513 */
514 public String getNameInNamespace()
515 throws NamingException {
516 throw new OperationNotSupportedException();
517 }
518
519 /**
520 * Searches in the named context or object for entries that satisfy the
521 * given search filter. Performs the search as specified by the search
522 * controls.
523 *
524 * @param name the name of the context or object to search
525 * @param filter the filter expression to use for the search; may not be
526 * null
527 * @param cons the search controls that control the search. If null,
528 * the default search controls are used (equivalent to
529 * (new SearchControls())).
530 * @return an enumeration of SearchResults of the objects that satisfy
531 * the filter; never null
532 * @exception javax.naming.NamingException if a naming exception is encountered
533 */
534 public NamingEnumeration search
535 (Name name, String filter, SearchControls cons)
536 throws NamingException {
537 return search(name.toString(), filter, cons);
538 }
539
540
541 /**
542 * Searches in the named context or object for entries that satisfy the
543 * given search filter. Performs the search as specified by the search
544 * controls.
545 *
546 * @param name the name of the context or object to search
547 * @param filter the filter expression to use for the search; may not be
548 * null
549 * @param cons the search controls that control the search. If null,
550 * the default search controls are used (equivalent to
551 * (new SearchControls())).
552 * @return an enumeration of SearchResults of the objects that satisfy
553 * the filter; never null
554 * @exception javax.naming.NamingException if a naming exception is encountered
555 */
556 public NamingEnumeration search(String name, String filter,
557 SearchControls cons)
558 throws NamingException {
559 throw new OperationNotSupportedException();
560 }
561
562
563 /**
564 * Searches in the named context or object for entries that satisfy the
565 * given search filter. Performs the search as specified by the search
566 * controls.
567 *
568 * @param name the name of the context or object to search
569 * @param filterExpr the filter expression to use for the search.
570 * The expression may contain variables of the form "{i}" where i is a
571 * nonnegative integer. May not be null.
572 * @param filterArgs the array of arguments to substitute for the
573 * variables in filterExpr. The value of filterArgs[i] will replace each
574 * occurrence of "{i}". If null, equivalent to an empty array.
575 * @param cons the search controls that control the search. If null, the
576 * default search controls are used (equivalent to (new SearchControls())).
577 * @return an enumeration of SearchResults of the objects that satisy the
578 * filter; never null
579 * @exception java.lang.ArrayIndexOutOfBoundsException if filterExpr contains {i}
580 * expressions where i is outside the bounds of the array filterArgs
581 * @exception javax.naming.NamingException if a naming exception is encountered
582 */
583 public NamingEnumeration search(Name name, String filterExpr,
584 Object[] filterArgs, SearchControls cons)
585 throws NamingException {
586 return search(name.toString(), filterExpr, filterArgs, cons);
587 }
588
589
590 /**
591 * Searches in the named context or object for entries that satisfy the
592 * given search filter. Performs the search as specified by the search
593 * controls.
594 *
595 * @param name the name of the context or object to search
596 * @param filterExpr the filter expression to use for the search.
597 * The expression may contain variables of the form "{i}" where i is a
598 * nonnegative integer. May not be null.
599 * @param filterArgs the array of arguments to substitute for the
600 * variables in filterExpr. The value of filterArgs[i] will replace each
601 * occurrence of "{i}". If null, equivalent to an empty array.
602 * @param cons the search controls that control the search. If null, the
603 * default search controls are used (equivalent to (new SearchControls())).
604 * @return an enumeration of SearchResults of the objects that satisy the
605 * filter; never null
606 * @exception java.lang.ArrayIndexOutOfBoundsException if filterExpr contains {i}
607 * expressions where i is outside the bounds of the array filterArgs
608 * @exception javax.naming.NamingException if a naming exception is encountered
609 */
610 public NamingEnumeration search(String name, String filterExpr,
611 Object[] filterArgs,
612 SearchControls cons)
613 throws NamingException {
614 throw new OperationNotSupportedException();
615 }
616
617
618 }
619