View Javadoc
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