1/*
2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.management.relation;
27
28import com.sun.jmx.mbeanserver.Util;
29import java.util.ArrayList;
30import java.util.Collection;
31import java.util.List;
32
33/**
34 * A RoleUnresolvedList represents a list of RoleUnresolved objects,
35 * representing roles not retrieved from a relation due to a problem
36 * encountered when trying to access (read or write) the roles.
37 *
38 * @since 1.5
39 */
40/* We cannot extend ArrayList<RoleUnresolved> because our legacy
41   add(RoleUnresolved) method would then override add(E) in ArrayList<E>,
42   and our return value is void whereas ArrayList.add(E)'s is boolean.
43   Likewise for set(int,RoleUnresolved).  Grrr.  We cannot use covariance
44   to override the most important methods and have them return
45   RoleUnresolved, either, because that would break subclasses that
46   override those methods in turn (using the original return type
47   of Object).  Finally, we cannot implement Iterable<RoleUnresolved>
48   so you could write
49       for (RoleUnresolved r : roleUnresolvedList)
50   because ArrayList<> implements Iterable<> and the same class cannot
51   implement two versions of a generic interface.  Instead we provide
52   the asList() method so you can write
53       for (RoleUnresolved r : roleUnresolvedList.asList())
54*/
55public class RoleUnresolvedList extends ArrayList<Object> {
56
57    private transient boolean typeSafe;
58    private transient boolean tainted;
59
60    /* Serial version */
61    private static final long serialVersionUID = 4054902803091433324L;
62
63    //
64    // Constructors
65    //
66
67    /**
68     * Constructs an empty RoleUnresolvedList.
69     */
70    public RoleUnresolvedList() {
71        super();
72    }
73
74    /**
75     * Constructs an empty RoleUnresolvedList with the initial capacity
76     * specified.
77     *
78     * @param initialCapacity  initial capacity
79     */
80    public RoleUnresolvedList(int initialCapacity) {
81        super(initialCapacity);
82    }
83
84    /**
85     * Constructs a {@code RoleUnresolvedList} containing the elements of the
86     * {@code List} specified, in the order in which they are returned by
87     * the {@code List}'s iterator. The {@code RoleUnresolvedList} instance has
88     * an initial capacity of 110% of the size of the {@code List}
89     * specified.
90     *
91     * @param list the {@code List} that defines the initial contents of
92     * the new {@code RoleUnresolvedList}.
93     *
94     * @exception IllegalArgumentException if the {@code list} parameter
95     * is {@code null} or if the {@code list} parameter contains any
96     * non-RoleUnresolved objects.
97     *
98     * @see ArrayList#ArrayList(java.util.Collection)
99     */
100    public RoleUnresolvedList(List<RoleUnresolved> list)
101        throws IllegalArgumentException {
102        // Check for null parameter
103        //
104        if (list == null)
105            throw new IllegalArgumentException("Null parameter");
106
107        // Check for non-RoleUnresolved objects
108        //
109        checkTypeSafe(list);
110
111        // Build the List<RoleUnresolved>
112        //
113        super.addAll(list);
114    }
115
116    /**
117     * Return a view of this list as a {@code List<RoleUnresolved>}.
118     * Changes to the returned value are reflected by changes
119     * to the original {@code RoleUnresolvedList} and vice versa.
120     *
121     * @return a {@code List<RoleUnresolved>} whose contents
122     * reflect the contents of this {@code RoleUnresolvedList}.
123     *
124     * <p>If this method has ever been called on a given
125     * {@code RoleUnresolvedList} instance, a subsequent attempt to add
126     * an object to that instance which is not a {@code RoleUnresolved}
127     * will fail with an {@code IllegalArgumentException}. For compatibility
128     * reasons, a {@code RoleUnresolvedList} on which this method has never
129     * been called does allow objects other than {@code RoleUnresolved}s to
130     * be added.</p>
131     *
132     * @throws IllegalArgumentException if this {@code RoleUnresolvedList}
133     * contains an element that is not a {@code RoleUnresolved}.
134     *
135     * @since 1.6
136     */
137    @SuppressWarnings("unchecked")
138    public List<RoleUnresolved> asList() {
139        if (!typeSafe) {
140            if (tainted)
141                checkTypeSafe(this);
142            typeSafe = true;
143        }
144        return Util.cast(this);
145    }
146
147    //
148    // Accessors
149    //
150
151    /**
152     * Adds the RoleUnresolved specified as the last element of the list.
153     *
154     * @param role - the unresolved role to be added.
155     *
156     * @exception IllegalArgumentException  if the unresolved role is null.
157     */
158    public void add(RoleUnresolved role)
159        throws IllegalArgumentException {
160
161        if (role == null) {
162            String excMsg = "Invalid parameter";
163            throw new IllegalArgumentException(excMsg);
164        }
165        super.add(role);
166    }
167
168    /**
169     * Inserts the unresolved role specified as an element at the position
170     * specified.
171     * Elements with an index greater than or equal to the current position are
172     * shifted up.
173     *
174     * @param index - The position in the list where the new
175     * RoleUnresolved object is to be inserted.
176     * @param role - The RoleUnresolved object to be inserted.
177     *
178     * @exception IllegalArgumentException  if the unresolved role is null.
179     * @exception IndexOutOfBoundsException if index is out of range
180     * (<code>index &lt; 0 || index &gt; size()</code>).
181     */
182    public void add(int index,
183                    RoleUnresolved role)
184        throws IllegalArgumentException,
185               IndexOutOfBoundsException {
186
187        if (role == null) {
188            String excMsg = "Invalid parameter";
189            throw new IllegalArgumentException(excMsg);
190        }
191
192        super.add(index, role);
193    }
194
195    /**
196     * Sets the element at the position specified to be the unresolved role
197     * specified.
198     * The previous element at that position is discarded.
199     *
200     * @param index - The position specified.
201     * @param role - The value to which the unresolved role element
202     * should be set.
203     *
204     * @exception IllegalArgumentException   if the unresolved role is null.
205     * @exception IndexOutOfBoundsException if index is out of range
206     * (<code>index &lt; 0 || index &gt;= size()</code>).
207     */
208     public void set(int index,
209                     RoleUnresolved role)
210         throws IllegalArgumentException,
211                IndexOutOfBoundsException {
212
213        if (role == null) {
214            String excMsg = "Invalid parameter";
215            throw new IllegalArgumentException(excMsg);
216        }
217
218        super.set(index, role);
219     }
220
221    /**
222     * Appends all the elements in the RoleUnresolvedList specified to the end
223     * of the list, in the order in which they are returned by the Iterator of
224     * the RoleUnresolvedList specified.
225     *
226     * @param roleList - Elements to be inserted into the list
227     * (can be null).
228     *
229     * @return true if this list changed as a result of the call.
230     *
231     * @exception IndexOutOfBoundsException  if accessing with an index
232     * outside of the list.
233     */
234    public boolean addAll(RoleUnresolvedList roleList)
235        throws IndexOutOfBoundsException {
236
237        if (roleList == null) {
238            return true;
239        }
240
241        return (super.addAll(roleList));
242    }
243
244    /**
245     * Inserts all of the elements in the RoleUnresolvedList specified into
246     * this list, starting at the specified position, in the order in which
247     * they are returned by the Iterator of the RoleUnresolvedList specified.
248     *
249     * @param index - Position at which to insert the first element from the
250     * RoleUnresolvedList specified.
251     * @param roleList - Elements to be inserted into the list.
252     *
253     * @return true if this list changed as a result of the call.
254     *
255     * @exception IllegalArgumentException  if the role is null.
256     * @exception IndexOutOfBoundsException if index is out of range
257     * (<code>index &lt; 0 || index &gt; size()</code>).
258     */
259    public boolean addAll(int index,
260                          RoleUnresolvedList roleList)
261        throws IllegalArgumentException,
262               IndexOutOfBoundsException {
263
264        if (roleList == null) {
265            String excMsg = "Invalid parameter";
266            throw new IllegalArgumentException(excMsg);
267        }
268
269        return (super.addAll(index, roleList));
270    }
271
272    /*
273     * Override all of the methods from ArrayList<Object> that might add
274     * a non-RoleUnresolved to the List, and disallow that if asList has
275     * ever been called on this instance.
276     */
277
278    @Override
279    public boolean add(Object o) {
280        if (!tainted)
281            tainted = isTainted(o);
282        if (typeSafe)
283            checkTypeSafe(o);
284        return super.add(o);
285    }
286
287    @Override
288    public void add(int index, Object element) {
289        if (!tainted)
290            tainted = isTainted(element);
291        if (typeSafe)
292            checkTypeSafe(element);
293        super.add(index, element);
294    }
295
296    @Override
297    public boolean addAll(Collection<?> c) {
298        if (!tainted)
299            tainted = isTainted(c);
300        if (typeSafe)
301            checkTypeSafe(c);
302        return super.addAll(c);
303    }
304
305    @Override
306    public boolean addAll(int index, Collection<?> c) {
307        if (!tainted)
308            tainted = isTainted(c);
309        if (typeSafe)
310            checkTypeSafe(c);
311        return super.addAll(index, c);
312    }
313
314    @Override
315    public Object set(int index, Object element) {
316        if (!tainted)
317            tainted = isTainted(element);
318        if (typeSafe)
319            checkTypeSafe(element);
320        return super.set(index, element);
321    }
322
323    /**
324     * IllegalArgumentException if o is a non-RoleUnresolved object.
325     */
326    private static void checkTypeSafe(Object o) {
327        try {
328            o = (RoleUnresolved) o;
329        } catch (ClassCastException e) {
330            throw new IllegalArgumentException(e);
331        }
332    }
333
334    /**
335     * IllegalArgumentException if c contains any non-RoleUnresolved objects.
336     */
337    private static void checkTypeSafe(Collection<?> c) {
338        try {
339            RoleUnresolved r;
340            for (Object o : c)
341                r = (RoleUnresolved) o;
342        } catch (ClassCastException e) {
343            throw new IllegalArgumentException(e);
344        }
345    }
346
347    /**
348     * Returns true if o is a non-RoleUnresolved object.
349     */
350    private static boolean isTainted(Object o) {
351        try {
352            checkTypeSafe(o);
353        } catch (IllegalArgumentException e) {
354            return true;
355        }
356        return false;
357    }
358
359    /**
360     * Returns true if c contains any non-RoleUnresolved objects.
361     */
362    private static boolean isTainted(Collection<?> c) {
363        try {
364            checkTypeSafe(c);
365        } catch (IllegalArgumentException e) {
366            return true;
367        }
368        return false;
369    }
370}
371