1 /*
   2  * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.naming;
  27 
  28 /**
  29   * This is the superclass of all exceptions thrown by
  30   * operations in the Context and DirContext interfaces.
  31   * The nature of the failure is described by the name of the subclass.
  32   * This exception captures the information pinpointing where the operation
  33   * failed, such as where resolution last proceeded to.
  34   * <ul>
  35   * <li> Resolved Name. Portion of name that has been resolved.
  36   * <li> Resolved Object. Object to which resolution of name proceeded.
  37   * <li> Remaining Name. Portion of name that has not been resolved.
  38   * <li> Explanation. Detail explaining why name resolution failed.
  39   * <li> Root Exception. The exception that caused this naming exception
  40   *                     to be thrown.
  41   *</ul>
  42   * null is an acceptable value for any of these fields. When null,
  43   * it means that no such information has been recorded for that field.
  44   *<p>
  45   * A NamingException instance is not synchronized against concurrent
  46   * multithreaded access. Multiple threads trying to access and modify
  47   * a single NamingException instance should lock the object.
  48   *<p>
  49   * This exception has been retrofitted to conform to
  50   * the general purpose exception-chaining mechanism.  The
  51   * <i>root exception</i> (or <i>root cause</i>) is the same object as the
  52   * <i>cause</i> returned by the {@link Throwable#getCause()} method.
  53   *
  54   * @author Rosanna Lee
  55   * @author Scott Seligman
  56   * @since 1.3
  57   */
  58 
  59 
  60 public class NamingException extends Exception {
  61     /**
  62      * Contains the part of the name that has been successfully resolved.
  63      * It is a composite name and can be null.
  64      * This field is initialized by the constructors.
  65      * You should access and manipulate this field
  66      * through its get and set methods.
  67      * @serial
  68      * @see #getResolvedName
  69      * @see #setResolvedName
  70      */
  71     protected Name resolvedName;
  72     /**
  73       * Contains the object to which resolution of the part of the name was
  74       * successful. Can be null.
  75       * This field is initialized by the constructors.
  76       * You should access and manipulate this field
  77       * through its get and set methods.
  78       * @serial
  79       * @see #getResolvedObj
  80       * @see #setResolvedObj
  81       */
  82     protected Object resolvedObj;
  83     /**
  84      * Contains the remaining name that has not been resolved yet.
  85      * It is a composite name and can be null.
  86      * This field is initialized by the constructors.
  87      * You should access and manipulate this field
  88      * through its get, set, "append" methods.
  89      * @serial
  90      * @see #getRemainingName
  91      * @see #setRemainingName
  92      * @see #appendRemainingName
  93      * @see #appendRemainingComponent
  94      */
  95     protected Name remainingName;
  96 
  97     /**
  98      * Contains the original exception that caused this NamingException to
  99      * be thrown. This field is set if there is additional
 100      * information that could be obtained from the original
 101      * exception, or if the original exception could not be
 102      * mapped to a subclass of NamingException.
 103      * Can be null.
 104      *<p>
 105      * This field predates the general-purpose exception chaining facility.
 106      * The {@link #initCause(Throwable)} and {@link #getCause()} methods
 107      * are now the preferred means of accessing this information.
 108      *
 109      * @serial
 110      * @see #getRootCause
 111      * @see #setRootCause(Throwable)
 112      * @see #initCause(Throwable)
 113      * @see #getCause
 114      */
 115     protected Throwable rootException = null;
 116 
 117     /**
 118      * Constructs a new NamingException with an explanation.
 119      * All unspecified fields are set to null.
 120      *
 121      * @param   explanation     A possibly null string containing
 122      *                          additional detail about this exception.
 123      * @see java.lang.Throwable#getMessage
 124      */
 125     public NamingException(String explanation) {
 126         super(explanation);
 127         resolvedName = remainingName = null;
 128         resolvedObj = null;
 129     }
 130 
 131     /**
 132       * Constructs a new NamingException.
 133       * All fields are set to null.
 134       */
 135     public NamingException() {
 136         super();
 137         resolvedName = remainingName = null;
 138         resolvedObj = null;
 139     }
 140 
 141     /**
 142      * Retrieves the leading portion of the name that was resolved
 143      * successfully.
 144      *
 145      * @return The part of the name that was resolved successfully.
 146      *          It is a composite name. It can be null, which means
 147      *          the resolved name field has not been set.
 148      * @see #getResolvedObj
 149      * @see #setResolvedName
 150      */
 151     public Name getResolvedName() {
 152         return resolvedName;
 153     }
 154 
 155     /**
 156      * Retrieves the remaining unresolved portion of the name.
 157      * @return The part of the name that has not been resolved.
 158      *          It is a composite name. It can be null, which means
 159      *          the remaining name field has not been set.
 160      * @see #setRemainingName
 161      * @see #appendRemainingName
 162      * @see #appendRemainingComponent
 163      */
 164     public Name getRemainingName() {
 165         return remainingName;
 166     }
 167 
 168     /**
 169      * Retrieves the object to which resolution was successful.
 170      * This is the object to which the resolved name is bound.
 171      *
 172      * @return The possibly null object that was resolved so far.
 173      *  null means that the resolved object field has not been set.
 174      * @see #getResolvedName
 175      * @see #setResolvedObj
 176      */
 177     public Object getResolvedObj() {
 178         return resolvedObj;
 179     }
 180 
 181     /**
 182       * Retrieves the explanation associated with this exception.
 183       *
 184       * @return The possibly null detail string explaining more
 185       *         about this exception. If null, it means there is no
 186       *         detail message for this exception.
 187       *
 188       * @see java.lang.Throwable#getMessage
 189       */
 190     public String getExplanation() {
 191         return getMessage();
 192     }
 193 
 194     /**
 195      * Sets the resolved name field of this exception.
 196      *<p>
 197      * <tt>name</tt> is a composite name. If the intent is to set
 198      * this field using a compound name or string, you must
 199      * "stringify" the compound name, and create a composite
 200      * name with a single component using the string. You can then
 201      * invoke this method using the resulting composite name.
 202      *<p>
 203      * A copy of <code>name</code> is made and stored.
 204      * Subsequent changes to <code>name</code> do not
 205      * affect the copy in this NamingException and vice versa.
 206      *
 207      * @param name The possibly null name to set resolved name to.
 208      *          If null, it sets the resolved name field to null.
 209      * @see #getResolvedName
 210      */
 211     public void setResolvedName(Name name) {
 212         if (name != null)
 213             resolvedName = (Name)(name.clone());
 214         else
 215             resolvedName = null;
 216     }
 217 
 218     /**
 219      * Sets the remaining name field of this exception.
 220      *<p>
 221      * <tt>name</tt> is a composite name. If the intent is to set
 222      * this field using a compound name or string, you must
 223      * "stringify" the compound name, and create a composite
 224      * name with a single component using the string. You can then
 225      * invoke this method using the resulting composite name.
 226      *<p>
 227      * A copy of <code>name</code> is made and stored.
 228      * Subsequent changes to <code>name</code> do not
 229      * affect the copy in this NamingException and vice versa.
 230      * @param name The possibly null name to set remaining name to.
 231      *          If null, it sets the remaining name field to null.
 232      * @see #getRemainingName
 233      * @see #appendRemainingName
 234      * @see #appendRemainingComponent
 235      */
 236     public void setRemainingName(Name name) {
 237         if (name != null)
 238             remainingName = (Name)(name.clone());
 239         else
 240             remainingName = null;
 241     }
 242 
 243     /**
 244      * Sets the resolved object field of this exception.
 245      * @param obj The possibly null object to set resolved object to.
 246      *            If null, the resolved object field is set to null.
 247      * @see #getResolvedObj
 248      */
 249     public void setResolvedObj(Object obj) {
 250         resolvedObj = obj;
 251     }
 252 
 253     /**
 254       * Add name as the last component in remaining name.
 255       * @param name The component to add.
 256       *         If name is null, this method does not do anything.
 257       * @see #setRemainingName
 258       * @see #getRemainingName
 259       * @see #appendRemainingName
 260       */
 261     public void appendRemainingComponent(String name) {
 262         if (name != null) {
 263             try {
 264                 if (remainingName == null) {
 265                     remainingName = new CompositeName();
 266                 }
 267                 remainingName.add(name);
 268             } catch (NamingException e) {
 269                 throw new IllegalArgumentException(e.toString());
 270             }
 271         }
 272     }
 273 
 274     /**
 275       * Add components from 'name' as the last components in
 276       * remaining name.
 277       *<p>
 278       * <tt>name</tt> is a composite name. If the intent is to append
 279       * a compound name, you should "stringify" the compound name
 280       * then invoke the overloaded form that accepts a String parameter.
 281       *<p>
 282       * Subsequent changes to <code>name</code> do not
 283       * affect the remaining name field in this NamingException and vice versa.
 284       * @param name The possibly null name containing ordered components to add.
 285       *                 If name is null, this method does not do anything.
 286       * @see #setRemainingName
 287       * @see #getRemainingName
 288       * @see #appendRemainingComponent
 289       */
 290     public void appendRemainingName(Name name) {
 291         if (name == null) {
 292             return;
 293         }
 294         if (remainingName != null) {
 295             try {
 296                 remainingName.addAll(name);
 297             } catch (NamingException e) {
 298                 throw new IllegalArgumentException(e.toString());
 299             }
 300         } else {
 301             remainingName = (Name)(name.clone());
 302         }
 303     }
 304 
 305     /**
 306       * Retrieves the root cause of this NamingException, if any.
 307       * The root cause of a naming exception is used when the service provider
 308       * wants to indicate to the caller a non-naming related exception
 309       * but at the same time wants to use the NamingException structure
 310       * to indicate how far the naming operation proceeded.
 311       *<p>
 312       * This method predates the general-purpose exception chaining facility.
 313       * The {@link #getCause()} method is now the preferred means of obtaining
 314       * this information.
 315       *
 316       * @return The possibly null exception that caused this naming
 317       *    exception. If null, it means no root cause has been
 318       *    set for this naming exception.
 319       * @see #setRootCause
 320       * @see #rootException
 321       * @see #getCause
 322       */
 323     public Throwable getRootCause() {
 324         return rootException;
 325     }
 326 
 327     /**
 328       * Records the root cause of this NamingException.
 329       * If <tt>e</tt> is <tt>this</tt>, this method does not do anything.
 330       *<p>
 331       * This method predates the general-purpose exception chaining facility.
 332       * The {@link #initCause(Throwable)} method is now the preferred means
 333       * of recording this information.
 334       *
 335       * @param e The possibly null exception that caused the naming
 336       *          operation to fail. If null, it means this naming
 337       *          exception has no root cause.
 338       * @see #getRootCause
 339       * @see #rootException
 340       * @see #initCause
 341       */
 342     public void setRootCause(Throwable e) {
 343         if (e != this) {
 344             rootException = e;
 345         }
 346     }
 347 
 348     /**
 349       * Returns the cause of this exception.  The cause is the
 350       * throwable that caused this naming exception to be thrown.
 351       * Returns <code>null</code> if the cause is nonexistent or
 352       * unknown.
 353       *
 354       * @return  the cause of this exception, or <code>null</code> if the
 355       *          cause is nonexistent or unknown.
 356       * @see #initCause(Throwable)
 357       * @since 1.4
 358       */
 359     public Throwable getCause() {
 360         return getRootCause();
 361     }
 362 
 363     /**
 364       * Initializes the cause of this exception to the specified value.
 365       * The cause is the throwable that caused this naming exception to be
 366       * thrown.
 367       *<p>
 368       * This method may be called at most once.
 369       *
 370       * @param  cause   the cause, which is saved for later retrieval by
 371       *         the {@link #getCause()} method.  A <tt>null</tt> value
 372       *         indicates that the cause is nonexistent or unknown.
 373       * @return a reference to this <code>NamingException</code> instance.
 374       * @throws IllegalArgumentException if <code>cause</code> is this
 375       *         exception.  (A throwable cannot be its own cause.)
 376       * @throws IllegalStateException if this method has already
 377       *         been called on this exception.
 378       * @see #getCause
 379       * @since 1.4
 380       */
 381     public Throwable initCause(Throwable cause) {
 382         super.initCause(cause);
 383         setRootCause(cause);
 384         return this;
 385     }
 386 
 387     /**
 388      * Generates the string representation of this exception.
 389      * The string representation consists of this exception's class name,
 390      * its detailed message, and if it has a root cause, the string
 391      * representation of the root cause exception, followed by
 392      * the remaining name (if it is not null).
 393      * This string is used for debugging and not meant to be interpreted
 394      * programmatically.
 395      *
 396      * @return The non-null string containing the string representation
 397      * of this exception.
 398      */
 399     public String toString() {
 400         String answer = super.toString();
 401 
 402         if (rootException != null) {
 403             answer += " [Root exception is " + rootException + "]";
 404         }
 405         if (remainingName != null) {
 406             answer += "; remaining name '" + remainingName + "'";
 407         }
 408         return answer;
 409     }
 410 
 411     /**
 412       * Generates the string representation in more detail.
 413       * This string representation consists of the information returned
 414       * by the toString() that takes no parameters, plus the string
 415       * representation of the resolved object (if it is not null).
 416       * This string is used for debugging and not meant to be interpreted
 417       * programmatically.
 418       *
 419       * @param detail If true, include details about the resolved object
 420       *                 in addition to the other information.
 421       * @return The non-null string containing the string representation.
 422       */
 423     public String toString(boolean detail) {
 424         if (!detail || resolvedObj == null) {
 425             return toString();
 426         } else {
 427             return (toString() + "; resolved object " + resolvedObj);
 428         }
 429     }
 430 
 431     /**
 432      * Use serialVersionUID from JNDI 1.1.1 for interoperability
 433      */
 434     private static final long serialVersionUID = -1299181962103167177L;
 435 };