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 }