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 }