1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package net.jini.core.entry; 19 20 import java.io.InvalidObjectException; 21 import java.io.IOException; 22 import java.io.PrintStream; 23 import java.io.PrintWriter; 24 import java.io.ObjectInputStream; 25 26 /** 27 * Thrown when one tries to get an <code>Entry</code> from a service, 28 * but the entry is unusable (due to serialization or other errors). 29 * Normally <code>partialEntry</code> points to an entry with as many 30 * fields as possible filled in, with the array <code>unusableFields</code> 31 * naming the fields that could not be deserialized and the array 32 * <code>nestedExceptions</code> having the corresponding exception. 33 * <p> 34 * If the serialized <code>Entry</code> was corrupt enough that no 35 * attempt could even be made to deserialize its fields, 36 * <code>partialEntry</code> and <code>unusableFields</code> will be 37 * <code>null</code>, and <code>nestedExceptions</code> will be an 38 * array with one element that is the offending exception. This will 39 * typically be because one or more of the classes of the <code>Entry</code> 40 * type itself cannot be loaded. 41 * <p> 42 * The names in <code>unusableFields</code> can be used together with 43 * the reflection mechanisms of <code>java.lang.reflect</code> to 44 * examine the full state of the object. 45 * 46 * @author Sun Microsystems, Inc. 47 * 48 * @since 1.0 49 */ 50 public class UnusableEntryException extends Exception { 51 static final long serialVersionUID = -2199083666668626172L; 52 //NOTE: Cannot implement @AtomicSerial until fields are private and final 53 // and all invariants can be enforced. 54 /** 55 * The partial entry. Fields that could not be deserialized 56 * will be <code>null</code>. 57 * 58 * @serial 59 */ 60 public Entry partialEntry; 61 62 /** 63 * The names of the unusable fields. If the entry was entirely 64 * unusable, <code>unusableFields</code> will be <code>null</code>. 65 * 66 * @serial 67 * @deprecated this field will be made private, use {@link #getUnusableFields() } 68 */ 69 public String[] unusableFields; 70 71 /** 72 * The exception that caused the failure for the corresponding 73 * field named in unusableFields. If the entry was entirely 74 * unusable, <code>nestedExceptions</code> will be an array with 75 * the one exception that prevented its use. 76 * 77 * @serial 78 * @deprecated this field will be made private, use {@link #getNestedExceptions() } 79 */ 80 public Throwable[] nestedExceptions; 81 82 /** 83 * Create an exception for the given partial entry and vectors of 84 * bad field names/nested exception pairs. 85 * 86 * @param partial the Entry object on which the exception occurred 87 * @param badFields a String array containing the bad field names 88 * @param exceptions an array of Throwable objects associated with the 89 * bad field names 90 * 91 * @throws IllegalArgumentException if <code>partial</code> is 92 * <code>null</code> and <code>badFields</code> is not 93 * <code>null</code> or <code>exceptions</code> does not have 94 * exactly one element or if <code>partial</code> is 95 * non-<code>null</code> and <code>badFields</code> and 96 * <code>exceptions</code> are not the same length 97 * 98 * @throws NullPointerException if <code>partial</code> is 99 * non-<code>null</code> and <code>badFields</code> or any 100 * element of <code>badFields</code> is <code>null</code>, or 101 * if <code>exceptions</code> or any element of 102 * <code>exceptions</code> is <code>null</code> 103 */ 104 public UnusableEntryException(Entry partial, String[] badFields, 105 Throwable[] exceptions) 106 { 107 super(); 108 //TODO, once fields are private check invariants prior to calling 109 // super() using static method. 110 if (partial == null) { 111 if (exceptions.length != 1) { 112 throw new IllegalArgumentException("If partial is null " + 113 "exceptions must have one element"); 114 } 115 116 if (badFields != null) { 117 throw new IllegalArgumentException("If partial is null " + 118 "badFields must be null"); 119 } 120 } else { 121 if (badFields.length != exceptions.length) { 122 throw new IllegalArgumentException("If partial is non-null " + 123 "badFields and exceptions must have same length"); 124 } 125 } 126 127 if (badFields != null) { 128 for (int i=0; i<badFields.length; i++) { 129 if (badFields[i] == null) 130 throw new NullPointerException("badFields has a null element"); 131 } 132 } 133 134 for (int i=0; i<exceptions.length; i++) { 135 if (exceptions[i] == null) 136 throw new NullPointerException("exceptions has a null element"); 137 } 138 139 partialEntry = partial; 140 unusableFields = badFields; 141 nestedExceptions = exceptions; 142 } 143 144 /** 145 * Create an exception for a nested exception that prevented even an 146 * attempt to build an entry. 147 * 148 * @param e a Throwable representing the nested exception 149 * @throws NullPointerException if <code>e</code> is <code>null</code> 150 */ 151 public UnusableEntryException(Throwable e) { 152 if (e == null) 153 throw new NullPointerException("e must be non-null"); 154 155 partialEntry = null; 156 unusableFields = null; 157 nestedExceptions = new Throwable[] { e }; 158 } 159 160 /** 161 * The names of the unusable fields. 162 * 163 * @return The names of the unusable fields or null if the entry was 164 * entirely unusable. 165 * @since 3.1.0 166 */ 167 public String [] getUnusableFields(){ 168 return unusableFields; 169 } 170 171 /** 172 * The exception that caused the failure for the corresponding 173 * field named in unusableFields. If the entry was entirely 174 * unusable, <code>nestedExceptions</code> will be an array with 175 * the one exception that prevented its use. 176 * 177 * @return The exception that caused the failure for the corresponding 178 * field named in getUnusableFields. 179 * @since 3.1.0 180 */ 181 public Throwable [] getNestedExceptions(){ 182 return nestedExceptions; 183 } 184 185 /** 186 * @throws InvalidObjectException if: 187 * <ul> 188 * <li> <code>partialEntry</code> is <code>null</code> and 189 * <code>unusableFields</code> is not <code>null</code> or 190 * <code>nestedExceptions</code> does not have exactly one 191 * element, 192 * <li> if <code>partialEntry</code> is non-<code>null</code> and 193 * <code>unusableFields</code> and 194 * <code>nestedExceptions</code> are not the same length, 195 * <li> if <code>partialEntry</code> is non-<code>null</code> and 196 * <code>unusableFields</code> is <code>null</code> or 197 * any element of <code>unusableFields</code> is 198 * <code>null</code>, or 199 * <li> if <code>nestedExceptions</code> or any element of 200 * <code>nestedExceptions</code> is <code>null</code> 201 * </ul> 202 * @param in ObjectInputStream 203 * @throws ClassNotFoundException if class not found. 204 * @throws IOException if a problem occurs during de-serialization. 205 */ 206 private void readObject(ObjectInputStream in) 207 throws IOException, ClassNotFoundException 208 { 209 in.defaultReadObject(); 210 211 if (partialEntry == null) { 212 if (nestedExceptions.length != 1) { 213 throw new InvalidObjectException("If partialEntry is null " + 214 "nestedExceptions must have one element"); 215 } 216 217 if (unusableFields != null) { 218 throw new InvalidObjectException("If partialEntry is null " + 219 "unusableFields must be null"); 220 } 221 } else { 222 if (unusableFields == null) 223 throw new InvalidObjectException("unusableFields is null"); 224 225 if (nestedExceptions == null) 226 throw new InvalidObjectException("nestedExceptions is null"); 227 228 if (unusableFields.length != nestedExceptions.length) { 229 throw new InvalidObjectException("If partialEntry is non-null " + 230 "unusableFields and nestedExceptions must have same length"); 231 } 232 } 233 234 if (unusableFields != null) { 235 for (int i=0; i<unusableFields.length; i++) { 236 if (unusableFields[i] == null) 237 throw new InvalidObjectException("unusableFields has a " + 238 "null element"); 239 } 240 } 241 242 for (int i=0; i<nestedExceptions.length; i++) { 243 if (nestedExceptions[i] == null) 244 throw new InvalidObjectException("nestedExceptions has a null " + 245 "element"); 246 } 247 } 248 249 /** 250 * @throws InvalidObjectException if called 251 */ 252 private void readObjectNoData() throws InvalidObjectException { 253 throw new InvalidObjectException( 254 "UnusableEntryExceptions should always have data"); 255 } 256 257 /** 258 * Calls {@link #printStackTrace(PrintStream) printStackTrace(System.err)}. 259 */ 260 public void printStackTrace() { 261 printStackTrace(System.err); 262 } 263 264 /** 265 * Calls {@link Exception#printStackTrace(PrintStream) 266 * super.printStackTrace(s)} and then calls {@link 267 * Throwable#printStackTrace(PrintStream) printStackTrace(s)} on 268 * each exception in <code>nestedExceptions</code>. 269 */ 270 public void printStackTrace(PrintStream s) { 271 synchronized (s) { 272 super.printStackTrace(s); 273 274 if (unusableFields == null) { 275 s.println("Total unmarshalling failure, cause was:"); 276 nestedExceptions[0].printStackTrace(s); 277 } else { 278 s.println("Partial unmarshalling failure"); 279 for (int i=0; i<nestedExceptions.length; i++) { 280 s.println(unusableFields[i] + 281 " field could not be unmarshalled because of:"); 282 nestedExceptions[i].printStackTrace(s); 283 } 284 } 285 } 286 } 287 288 /** 289 * Calls {@link Exception#printStackTrace(PrintWriter) 290 * super.printStackTrace(s)} and then calls {@link 291 * Throwable#printStackTrace(PrintWriter) printStackTrace(s)} on 292 * each exception in <code>nestedExceptions</code>. 293 */ 294 public void printStackTrace(PrintWriter s) { 295 synchronized (s) { 296 super.printStackTrace(s); 297 298 if (unusableFields == null) { 299 s.println("Total unmarshalling failure, cause was:"); 300 nestedExceptions[0].printStackTrace(s); 301 } else { 302 s.println("Partial unmarshalling failure"); 303 for (int i=0; i<nestedExceptions.length; i++) { 304 s.println(unusableFields[i] + 305 " field could not be unmarshalled because of:"); 306 nestedExceptions[i].printStackTrace(s); 307 } 308 } 309 } 310 } 311 }