    001    /* ========================================================================
    002     * JCommon : a free general purpose class library for the Java(tm) platform
    003     * ========================================================================
    004     *
    005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jcommon/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * -----------------------
    028     * AbstractObjectList.java
    029     * -----------------------
    030     * (C)opyright 2003, 2004, by Object Refinery Limited and Contributors.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   Bill Kelemen;
    034     *                   Nicolas Brodu
    035     *
    036     * $Id: AbstractObjectList.java,v 1.5 2005/10/18 13:24:19 mungady Exp $
    037     *
    038     * Changes
    039     * -------
    040     * 13-Aug-2003 : Version 1, based on ObjectList (DG);
    041     * 24-Aug-2003 : Fixed size (BK);
    042     * 15-Sep-2003 : Fix serialization for subclasses (ShapeList, PaintList) (NB);
    043     */
    044
    045    package org.jfree.util;
    046
    047    import java.io.IOException;
    048    import java.io.ObjectInputStream;
    049    import java.io.ObjectOutputStream;
    050    import java.io.Serializable;
    051    import java.util.Arrays;
    052
    053    /**
    054     * A list of objects that can grow as required.
    055     *
    056     * @author David Gilbert
    057     */
    058    public class AbstractObjectList implements Cloneable, Serializable {
    059
    060        /** For serialization. */
    061        private static final long serialVersionUID = 7789833772597351595L;
    062
    063        /** The default initial capacity of the list. */
    064        public static final int DEFAULT_INITIAL_CAPACITY = 8;
    065
    066        /** Storage for the objects. */
    067        private transient Object[] objects;
    068
    069        /** The current list size. */
    070        private int size = 0;
    071
    072        /** The default increment. */
    073        private int increment = DEFAULT_INITIAL_CAPACITY;
    074
    075        /**
    076         * Creates a new list with the default initial capacity.
    077         */
    078        protected AbstractObjectList() {
    079            this(DEFAULT_INITIAL_CAPACITY);
    080        }
    081
    082        /**
    083         * Creates a new list.
    084         *
    085         * @param initialCapacity  the initial capacity.
    086         */
    087        protected AbstractObjectList(final int initialCapacity) {
    088            this (initialCapacity, initialCapacity);
    089        }
    090
    091        /**
    092         * Creates a new list.
    093         *
    094         * @param initialCapacity  the initial capacity.
    095         * @param increment  the increment.
    096         */
    097        protected AbstractObjectList(final int initialCapacity,
    098                                     final int increment) {
    099            this.objects = new Object[initialCapacity];
    100            this.increment = increment;
    101        }
    102
    103        /**
    104         * Returns the object at the specified index, if there is one, or
    105         * <code>null</code>.
    106         *
    107         * @param index  the object index.
    108         *
    109         * @return The object or <code>null</code>.
    110         */
    111        protected Object get(final int index) {
    112            Object result = null;
    113            if (index >= 0 && index < this.size) {
    114                result = this.objects[index];
    115            }
    116            return result;
    117        }
    118
    119        /**
    120         * Sets an object reference (overwriting any existing object).
    121         *
    122         * @param index  the object index.
    123         * @param object  the object (<code>null</code> permitted).
    124         */
    125        protected void set(final int index, final Object object) {
    126            if (index < 0) {
    127                throw new IllegalArgumentException("Requires index >= 0.");
    128            }
    129            if (index >= this.objects.length) {
    130                final Object[] enlarged = new Object[index + this.increment];
    131                System.arraycopy(this.objects, 0, enlarged, 0, this.objects.length);
    132                this.objects = enlarged;
    133            }
    134            this.objects[index] = object;
    135            this.size = Math.max(this.size, index + 1);
    136        }
    137
    138        /**
    139         * Clears the list.
    140         */
    141        public void clear() {
    142            Arrays.fill(this.objects, null);
    143            this.size = 0;
    144        }
    145
    146        /**
    147         * Returns the size of the list.
    148         *
    149         * @return The size of the list.
    150         */
    151        public int size() {
    152            return this.size;
    153        }
    154
    155        /**
    156         * Returns the index of the specified object, or -1 if the object is not in
    157         * the list.
    158         *
    159         * @param object  the object.
    160         *
    161         * @return The index or -1.
    162         */
    163        protected int indexOf(final Object object) {
    164            for (int index = 0; index < this.size; index++) {
    165                if (this.objects[index] == object) {
    166                    return (index);
    167                }
    168            }
    169            return -1;
    170        }
    171
    172        /**
    173         * Tests this list for equality with another object.
    174         *
    175         * @param obj  the object to test.
    176         *
    177         * @return A boolean.
    178         */
    179        public boolean equals(final Object obj) {
    180
    181            if (obj == null) {
    182                return false;
    183            }
    184
    185            if (obj == this) {
    186                return true;
    187            }
    188
    189            if (!(obj instanceof AbstractObjectList)) {
    190                return false;
    191            }
    192
    193            final AbstractObjectList other = (AbstractObjectList) obj;
    194            final int listSize = size();
    195            for (int i = 0; i < listSize; i++) {
    196               if (!ObjectUtilities.equal(get(i), other.get(i))) {
    197                   return false;
    198               }
    199            }
    200            return true;
    201        }
    202
    203        /**
    204         * Returns a hash code value for the object.
    205         *
    206         * @return the hashcode
    207         */
    208        public int hashCode() {
    209            return super.hashCode();
    210        }
    211
    212        /**
    213         * Clones the list of objects.  The objects in the list are not cloned, so
    214         * this is method makes a 'shallow' copy of the list.
    215         *
    216         * @return A clone.
    217         *
    218         * @throws CloneNotSupportedException if an item in the list does not
    219         *         support cloning.
    220         */
    221        public Object clone() throws CloneNotSupportedException {
    222
    223            final AbstractObjectList clone = (AbstractObjectList) super.clone();
    224            if (this.objects != null) {
    225                clone.objects = new Object[this.objects.length];
    226                System.arraycopy(
    227                    this.objects, 0, clone.objects, 0, this.objects.length
    228                );
    229            }
    230            return clone;
    231
    232        }
    233
    234        /**
    235         * Provides serialization support.
    236         *
    237         * @param stream  the output stream.
    238         *
    239         * @throws IOException  if there is an I/O error.
    240         */
    241        private void writeObject(final ObjectOutputStream stream)
    242            throws IOException {
    243
    244            stream.defaultWriteObject();
    245            final int count = size();
    246            stream.writeInt(count);
    247            for (int i = 0; i < count; i++) {
    248                final Object object = get(i);
    249                if (object != null && object instanceof Serializable) {
    250                    stream.writeInt(i);
    251                    stream.writeObject(object);
    252                }
    253                else {
    254                    stream.writeInt(-1);
    255                }
    256            }
    257
    258        }
    259
    260        /**
    261         * Provides serialization support.
    262         *
    263         * @param stream  the input stream.
    264         *
    265         * @throws IOException  if there is an I/O error.
    266         * @throws ClassNotFoundException  if there is a classpath problem.
    267         */
    268        private void readObject(final ObjectInputStream stream)
    269            throws IOException, ClassNotFoundException {
    270
    271            stream.defaultReadObject();
    272            this.objects = new Object[this.size];
    273            final int count = stream.readInt();
    274            for (int i = 0; i < count; i++) {
    275                final int index = stream.readInt();
    276                if (index != -1) {
    277                    set(index, stream.readObject());
    278                }
    279            }
    280
    281        }
    282
    283    }