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 19 package net.jini.discovery; 20 21 import java.io.IOException; 22 import java.io.InvalidObjectException; 23 import java.io.ObjectInputStream; 24 import java.io.ObjectOutputStream; 25 import java.rmi.MarshalledObject; 26 import net.jini.core.lookup.ServiceRegistrar; 27 import org.apache.river.api.io.AtomicException; 28 import org.apache.river.api.io.AtomicSerial; 29 import org.apache.river.api.io.AtomicSerial.GetArg; 30 import org.apache.river.api.io.Valid; 31 32 /** 33 * When unmarshalling an instance of <code>MarshalledObject</code>, different 34 * exceptions can occur. An <code>IOException</code> can occur while 35 * deserializing the object from its internal representation. A 36 * <code>ClassNotFoundException</code> can occur if, while deserializing 37 * the object from its internal representation, either the class file of 38 * the object cannot be found, or the class file of either an interface 39 * or a class referenced by the object being deserialized cannot be found. 40 * Typically, a <code>ClassNotFoundException</code> occurs when the codebase 41 * from which to retrieve the needed class file is not currently available. 42 * <p> 43 * This class provides a mechanism that clients of the lookup discovery 44 * service may use for efficient handling of the exceptions that may 45 * occur when unmarshalling elements of a set of marshalled instances 46 * of the <code>ServiceRegistrar</code> interface. When elements in such 47 * a set are unmarshalled, the <code>LookupUnmarshalException</code> class 48 * may be used to collect and report pertinent information generated when 49 * failure occurs while unmarshalling the elements of the set. 50 * <p> 51 * The information that may be of interest to entities that receive this 52 * exception class is contained in the following fields: a set of 53 * <code>ServiceRegistrar</code> instances in which each element is the 54 * result of a successful unmarshalling attempt, a set of marshalled instances 55 * of <code>ServiceRegistrar</code> in which each element could not be 56 * successfully unmarshalled, and a set of exceptions (<code>IOException</code>, 57 * <code>ClassNotFoundException</code>, or some unchecked exception) in which 58 * each element corresponds to one of the unmarshalling failures. 59 * <p> 60 * Thus, when exceptional conditions occur while unmarshalling a set of 61 * marshalled instances of <code>ServiceRegistrar</code>, this class can 62 * be used not only to indicate that an exceptional condition has occurred, 63 * but also to provide information that can be used to perform error handling 64 * activities such as: determining if it is feasible to continue with 65 * processing, reporting exceptions, attempting recovery, and debugging. 66 * <p> 67 * Note that this exception class should be used only to report exceptional 68 * conditions occurring when unmarshalling a set of marshalled instances 69 * of the <code>ServiceRegistrar</code> interface. 70 * 71 * @author Sun Microsystems, Inc. 72 * 73 * @see net.jini.core.lookup.ServiceRegistrar 74 */ 75 @AtomicSerial 76 public class LookupUnmarshalException extends AtomicException { 77 78 private static final long serialVersionUID = 2956893184719950537L; 79 80 /** 81 * Array containing the set of instances of <code>ServiceRegistrar</code> 82 * that were successfully unmarshalled during the process in which at 83 * least one failure occurred. This set may be <code>null</code> or 84 * have zero length. 85 * 86 * @serial 87 */ 88 private final ServiceRegistrar[] registrars; 89 90 /** 91 * Array containing the set of <code>ServiceRegistrar</code> instances 92 * that could not be unmarshalled. This set should not be <code>null</code> 93 * and should contain at least one element. 94 * 95 * @serial 96 */ 97 private final MarshalledObject[] marshalledRegistrars; 98 99 /** 100 * Array containing the set of exceptions that occurred during the 101 * unmarshalling process. Each element in this set should be an instance 102 * of <code>IOException</code>, <code>ClassNotFoundException</code>, or 103 * some unchecked exception. Furthermore, there should be a one-to-one 104 * correspondence between each element in this set and each element in 105 * the set of still-to-be-unmarshalled <code>ServiceRegistrar</code> 106 * instances. That is, the element of this set corresponding to index i 107 * should be an instance of the exception that occurred while attempting 108 * to unmarshal the element at index i of <code>marshalledRegistrars</code>. 109 * This set should not be <code>null</code> and should contain at least 110 * one element. 111 * 112 * @serial 113 */ 114 private final Throwable[] exceptions; 115 116 /** 117 * Constructs a new instance of <code>LookupUnmarshalException</code>. 118 * 119 * @param registrars Array containing the set of instances of 120 * <code>ServiceRegistrar</code> that were 121 * successfully unmarshalled. 122 * 123 * @param marshalledRegistrars Array containing the set of marshalled 124 * <code>ServiceRegistrar</code> instances 125 * that could not be unmarshalled. 126 * 127 * @param exceptions Array containing the set of exceptions that 128 * occurred during the unmarshalling process. 129 * Each element in this set should be an 130 * instance of <code>IOException</code>, 131 * <code>ClassNotFoundException</code>, or 132 * some unchecked exception. Furthermore, 133 * there should be a one-to-one correspondence 134 * between each element in this set and 135 * each element in the 136 * <code>marshalledRegistrars</code> parameter. 137 * <p> 138 * That is, the element of this set 139 * corresponding to index i should be an 140 * instance of the exception that occurred 141 * while attempting to unmarshal the element 142 * at index i of the 143 * <code>marshalledRegistrars</code> parameter. 144 * 145 * @throws java.lang.NullPointerException this exception occurs 146 * when <code>null</code> is input for either the 147 * <code>marshalledRegistrars</code> parameter or the 148 * <code>exceptions</code> parameter. 149 * @throws java.lang.IllegalArgumentException this exception occurs when 150 * either the <code>marshalledRegistrars</code> parameter or the 151 * <code>exceptions</code> parameter has zero length; or when the 152 * lengths of those two parameters are not equal. 153 */ 154 public LookupUnmarshalException(ServiceRegistrar[] registrars, 155 MarshalledObject[] marshalledRegistrars, 156 Throwable[] exceptions) 157 { 158 this(registrars, marshalledRegistrars, exceptions, 159 check(registrars, marshalledRegistrars, exceptions)); 160 }//end constructor 161 162 private LookupUnmarshalException(ServiceRegistrar[] registrars, 163 MarshalledObject[] marshalledRegistrars, 164 Throwable[] exceptions, 165 boolean check) 166 { 167 super(); 168 this.registrars = registrars != null ? registrars.clone(): null; 169 this.marshalledRegistrars = marshalledRegistrars.clone(); 170 this.exceptions = exceptions.clone(); 171 } 172 173 /** 174 * Constructs a new instance of <code>LookupUnmarshalException</code>. 175 * 176 * @param registrars Array containing the set of instances of 177 * <code>ServiceRegistrar</code> that were 178 * successfully unmarshalled. 179 * 180 * @param marshalledRegistrars Array containing the set of marshalled 181 * <code>ServiceRegistrar</code> instances 182 * that could not be unmarshalled. 183 * 184 * @param exceptions Array containing the set of exceptions that 185 * occurred during the unmarshalling process. 186 * Each element in this set should be an 187 * instance of <code>IOException</code>, 188 * <code>ClassNotFoundException</code>, or 189 * some unchecked exception. Furthermore, 190 * there should be a one-to-one correspondence 191 * between each element in this set and 192 * each element in the 193 * <code>marshalledRegistrars</code> parameter. 194 * <p> 195 * That is, the element of this set 196 * corresponding to index i should be an 197 * instance of the exception that occurred 198 * while attempting to unmarshal the element 199 * at index i of the 200 * <code>marshalledRegistrars</code> parameter. 201 * 202 * @param message <code>String</code> describing the nature 203 * of the exception 204 * 205 * @throws java.lang.NullPointerException this exception occurs 206 * when <code>null</code> is input for either the 207 * <code>marshalledRegistrars</code> parameter or the 208 * <code>exceptions</code> parameter. 209 * @throws java.lang.IllegalArgumentException this exception occurs when 210 * either the <code>marshalledRegistrars</code> parameter or the 211 * <code>exceptions</code> parameter has zero length; or when the 212 * lengths of those two parameters are not equal. 213 */ 214 public LookupUnmarshalException(ServiceRegistrar[] registrars, 215 MarshalledObject[] marshalledRegistrars, 216 Throwable[] exceptions, 217 String message) 218 { 219 this(registrars, marshalledRegistrars, exceptions, message, 220 check(registrars,marshalledRegistrars,exceptions)); 221 }//end constructor 222 223 private LookupUnmarshalException(ServiceRegistrar[] registrars, 224 MarshalledObject[] marshalledRegistrars, 225 Throwable[] exceptions, 226 String message, 227 boolean check) 228 { 229 super(message); 230 this.registrars = registrars != null ? registrars.clone() : null; 231 this.marshalledRegistrars = marshalledRegistrars.clone(); 232 this.exceptions = exceptions.clone(); 233 234 } 235 236 /** 237 * AtomicSerial constructor. 238 * 239 * @param arg atomic deserialization parameter 240 * @throws IOException if there are I/O errors while reading from GetArg's 241 * underlying <code>InputStream</code> 242 */ 243 public LookupUnmarshalException(GetArg arg) throws IOException{ 244 this(arg, 245 Valid.copy(arg.get("registrars", null, ServiceRegistrar[].class)), 246 Valid.copy(arg.get("marshalledRegistrars", null, MarshalledObject[].class)), 247 Valid.copy(arg.get("exceptions", null, Throwable[].class)) 248 ); 249 } 250 251 /** 252 * Validate state. 253 * @param arg 254 * @param registrars 255 * @param marshalledRegistrars 256 * @param exceptions 257 * @throws IOException 258 */ 259 private LookupUnmarshalException(GetArg arg, 260 ServiceRegistrar[] registrars, 261 MarshalledObject[] marshalledRegistrars, 262 Throwable[] exceptions) throws IOException 263 { 264 this(arg, registrars, marshalledRegistrars, exceptions, 265 validate(registrars, marshalledRegistrars, exceptions)); 266 } 267 268 /** 269 * Invariants have been checked, let superclass check, then assign fields. 270 * @param arg 271 * @param registrars 272 * @param marshalledRegistrars 273 * @param exceptions 274 * @param check 275 * @throws IOException 276 */ 277 private LookupUnmarshalException(GetArg arg, 278 ServiceRegistrar[] registrars, 279 MarshalledObject[] marshalledRegistrars, 280 Throwable[] exceptions, 281 boolean check) throws IOException 282 { 283 super(arg); // Super has to check it's invariants. 284 this.registrars = registrars; 285 this.marshalledRegistrars = marshalledRegistrars; 286 this.exceptions = exceptions; 287 } 288 289 /** 290 * validation of serial form. 291 * @param registrars 292 * @param marshalledRegistrars 293 * @param exceptions 294 * @return 295 * @throws InvalidObjectException 296 */ 297 private static boolean validate(ServiceRegistrar[] registrars, 298 MarshalledObject[] marshalledRegistrars, 299 Throwable[] exceptions) throws InvalidObjectException 300 { 301 302 if(marshalledRegistrars == null) { 303 throw new InvalidObjectException 304 ("LookupUnmarshalException.readObject " 305 +"failure - marshalledRegistrars field is null"); 306 }//endif 307 if(exceptions == null) { 308 throw new InvalidObjectException 309 ("LookupUnmarshalException.readObject " 310 +"failure - exceptions field is null"); 311 }//endif 312 if(marshalledRegistrars.length == 0) { 313 throw new InvalidObjectException 314 ("LookupUnmarshalException.readObject " 315 +"failure - marshalledRegistrars.length == 0"); 316 }//endif 317 if(exceptions.length != marshalledRegistrars.length) { 318 throw new InvalidObjectException 319 ("LookupUnmarshalException.readObject failure - " 320 +"exceptions.length ("+exceptions.length 321 +") is not equal to marshalledRegistrars.length " 322 +"("+marshalledRegistrars.length+")"); 323 } 324 return true; 325 } 326 327 /** 328 * Accessor method that returns an array consisting of instances of 329 * <code>ServiceRegistrar</code>, where each element of the array 330 * corresponds to a successfully unmarshalled object. Note that a copy 331 * is returned on each invocation of this method. 332 * 333 * @return array of instances of <code>ServiceRegistrar</code>, where 334 * each element corresponds to a successfully unmarshalled object. 335 */ 336 public ServiceRegistrar[] getRegistrars() { 337 return registrars != null ? registrars.clone(): null; 338 }//end getRegistrars 339 340 /** 341 * Accessor method that returns an array consisting of instances of 342 * <code>MarshalledObject</code>, where each element of the array is a 343 * marshalled instance of the <code>ServiceRegistrar</code> interface, 344 * and corresponds to an object that could not be successfully 345 * unmarshalled. Note that a copy is returned on each invocation 346 * of this method. 347 * 348 * @return array of marshalled instances of <code>ServiceRegistrar</code>, 349 * where each element corresponds to an object in which failure 350 * occurred while attempting to unmarshal the object. 351 */ 352 public MarshalledObject[] getMarshalledRegistrars() { 353 return marshalledRegistrars.clone(); 354 }//end getMarshalledRegistrars 355 356 /** 357 * Accessor method that returns an array consisting of instances of 358 * <code>Throwable</code>, where each element of the array corresponds 359 * to one of the exceptions that occurred during the unmarshalling 360 * process. Note that a copy is returned on each invocation 361 * of this method. 362 * <p> 363 * Each element in the return set should be an instance of 364 * <code>IOException</code>, <code>ClassNotFoundException</code>, or 365 * some unchecked exception. Additionally, there should be a one-to-one 366 * correspondence between each element in the array returned by this method 367 * and the array returned by the <code>getMarshalledRegistrars</code> 368 * method. That is, the i-th element of the set returned by this method 369 * should be an instance of the exception that occurred while attempting 370 * to unmarshal the i-th element of the set returned by the method 371 * <code>getMarshalledRegistrars</code>. 372 * </p> 373 * @return array of instances of <code>Throwable</code>, where each element 374 * corresponds to one of the exceptions that occurred during 375 * the unmarshalling process. 376 */ 377 public Throwable[] getExceptions() { 378 return exceptions.clone(); 379 }//end getExceptions 380 381 /** 382 * Checks the state of this class prior to constructing 383 * 384 * @param registrars Array containing the set of instances of 385 * <code>ServiceRegistrar</code> that were 386 * successfully unmarshalled. 387 * 388 * @param marshalledRegistrars Array containing the set of marshalled 389 * <code>ServiceRegistrar</code> instances 390 * that could not be unmarshalled. 391 * 392 * @param exceptions Array containing the set of exceptions that 393 * occurred during the unmarshalling process. 394 * 395 * @throws java.lang.NullPointerException this exception occurs 396 * when <code>null</code> is input for either the 397 * <code>marshalledRegistrars</code> parameter or the 398 * <code>exceptions</code> parameter. 399 * @throws java.lang.IllegalArgumentException this exception occurs when 400 * either the <code>marshalledRegistrars</code> parameter or the 401 * <code>exceptions</code> parameter has zero length; or when the 402 * lengths of those two parameters are not equal. 403 */ 404 private static boolean check(ServiceRegistrar[] registrars, 405 MarshalledObject[] marshalledRegistrars, 406 Throwable[] exceptions) { 407 /* Verify the input arguments */ 408 if(marshalledRegistrars == null) { 409 throw new NullPointerException 410 ("marshalledRegistrars cannot be null"); 411 }//endif 412 if(exceptions == null) { 413 throw new NullPointerException("exceptions cannot be null"); 414 }//endif 415 if(marshalledRegistrars.length == 0) { 416 throw new IllegalArgumentException 417 ("marshalledRegistrars has 0 length"); 418 }//endif 419 if(exceptions.length != marshalledRegistrars.length) { 420 throw new IllegalArgumentException 421 ("exceptions.length ("+exceptions.length 422 +") is not equal to marshalledRegistrars.length " 423 +"("+marshalledRegistrars.length+")"); 424 }//endif 425 return true; 426 }//end check 427 428 private void writeObject(ObjectOutputStream out) throws IOException 429 { 430 out.defaultWriteObject(); 431 } 432 433 /** 434 * When an instance of this class is deserialized, this method is 435 * automatically invoked. This implementation of this method validates 436 * the state of the deserialized instance. 437 * 438 * @throws InvalidObjectException if the state of the 439 * deserialized instance of this class is found to be invalid. 440 */ 441 private void readObject(ObjectInputStream s) 442 throws IOException, ClassNotFoundException 443 { 444 s.defaultReadObject(); 445 /* Verify marshalledRegistrars and exceptions fields */ 446 validate(registrars, marshalledRegistrars, exceptions); 447 448 }//end readObject 449 450 }//end class LookupUnmarshalException