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; 18 19 import java.io.IOException; 20 import java.io.ObjectOutputStream; 21 import java.io.Serializable; 22 23 import javax.naming.Name; 24 25 import org.springframework.core.NestedRuntimeException; 26 27 /** 28 * Base class for exception thrown by the framework whenever it encounters a 29 * problem related to LDAP. 30 * 31 * @author Ulrik Sandberg 32 * @since 1.2 33 */ 34 public abstract class NamingException extends NestedRuntimeException { 35 36 private Throwable cause; 37 38 /** 39 * Overrides {@link NestedRuntimeException#getCause()} since serialization 40 * always tries to serialize the base class before the subclass. Our 41 * <tt>cause</tt> may have a <tt>resolvedObj</tt> that is not 42 * serializable. By storing the cause in this class, we get a chance at 43 * temporarily nulling the cause before serialization, thus in effect making 44 * the current instance serializable. 45 */ 46 public Throwable getCause() { 47 // Even if you cannot set the cause of this exception other than through 48 // the constructor, we check for the cause being "this" here, as the cause 49 // could still be set to "this" via reflection: for example, by a remoting 50 // deserializer like Hessian's. 51 return (this.cause == this ? null : this.cause); 52 } 53 54 /** 55 * Constructor that takes a message. 56 * 57 * @param msg 58 * the detail message 59 */ 60 public NamingException(String msg) { 61 super(msg); 62 } 63 64 /** 65 * Constructor that allows a message and a root cause. 66 * 67 * @param msg 68 * the detail message 69 * @param cause 70 * the cause of the exception. This argument is generally 71 * expected to be a proper subclass of 72 * {@link javax.naming.NamingException}. 73 */ 74 public NamingException(String msg, Throwable cause) { 75 super(msg); 76 this.cause = cause; 77 } 78 79 /** 80 * Constructor that allows a plain root cause, intended for subclasses 81 * mirroring corresponding <code>javax.naming</code> exceptions. 82 * 83 * @param cause 84 * the cause of the exception. This argument is generally 85 * expected to be a proper subclass of 86 * {@link javax.naming.NamingException}. 87 */ 88 public NamingException(Throwable cause) { 89 this(cause != null ? cause.getMessage() : null, cause); 90 } 91 92 /** 93 * Convenience method to get the explanation associated with this exception, 94 * if the root cause was an instance of {@link javax.naming.NamingException}. 95 * 96 * @return a detail string explaining more about this exception if the root 97 * cause is an instance of javax.naming.NamingException, or 98 * <code>null</code> if there is no detail message for this 99 * exception 100 */ 101 public String getExplanation() { 102 if (getCause() instanceof javax.naming.NamingException) { 103 return ((javax.naming.NamingException) getCause()).getExplanation(); 104 } 105 return null; 106 } 107 108 /** 109 * Convenience method to get the unresolved part of the name associated with 110 * this exception, if the root cause was an instance of 111 * {@link javax.naming.NamingException}. 112 * 113 * @return a composite name describing the part of the name that has not 114 * been resolved if the root cause is an instance of 115 * javax.naming.NamingException, or <code>null</code> if the 116 * remaining name field has not been set 117 */ 118 public Name getRemainingName() { 119 if (getCause() instanceof javax.naming.NamingException) { 120 return ((javax.naming.NamingException) getCause()) 121 .getRemainingName(); 122 } 123 return null; 124 } 125 126 /** 127 * Convenience method to get the leading portion of the resolved name 128 * associated with this exception, if the root cause was an instance of 129 * {@link javax.naming.NamingException}. 130 * 131 * @return a composite name describing the the leading portion of the name 132 * that was resolved successfully if the root cause is an instance 133 * of javax.naming.NamingException, or <code>null</code> if the 134 * resolved name field has not been set 135 */ 136 public Name getResolvedName() { 137 if (getCause() instanceof javax.naming.NamingException) { 138 return ((javax.naming.NamingException) getCause()) 139 .getResolvedName(); 140 } 141 return null; 142 } 143 144 /** 145 * Convenience method to get the resolved object associated with this 146 * exception, if the root cause was an instance of 147 * {@link javax.naming.NamingException}. 148 * 149 * @return the object that was resolved so far if the root cause is an 150 * instance of javax.naming.NamingException, or <code>null</code> 151 * if the resolved object field has not been set 152 */ 153 public Object getResolvedObj() { 154 if (getCause() instanceof javax.naming.NamingException) { 155 return ((javax.naming.NamingException) getCause()).getResolvedObj(); 156 } 157 return null; 158 } 159 160 /** 161 * Checks if the <tt>resolvedObj</tt> of the causing exception is 162 * suspected to be non-serializable, and if so temporarily nulls it before 163 * calling the default serialization mechanism. 164 * 165 * @param stream 166 * the stream onto which this object is serialized 167 * @throws IOException 168 * if there is an error writing this object to the stream 169 */ 170 private void writeObject(ObjectOutputStream stream) throws IOException { 171 Object resolvedObj = getResolvedObj(); 172 boolean serializable = resolvedObj instanceof Serializable; 173 if (resolvedObj != null && !serializable) { 174 // the cause is of this type, since resolvedObj is not null 175 javax.naming.NamingException namingException = (javax.naming.NamingException) getCause(); 176 namingException.setResolvedObj(null); 177 try { 178 stream.defaultWriteObject(); 179 } finally { 180 namingException.setResolvedObj(resolvedObj); 181 } 182 } else { 183 stream.defaultWriteObject(); 184 } 185 } 186 }