001 /**
002 * ========================================
003 * JFreeReport : a free Java report library
004 * ========================================
005 *
006 * Project Info: http://reporting.pentaho.org/
007 *
008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009 *
010 * This library is free software; you can redistribute it and/or modify it under the terms
011 * of the GNU Lesser General Public License as published by the Free Software Foundation;
012 * either version 2.1 of the License, or (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public License along with this
019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020 * Boston, MA 02111-1307, USA.
021 *
022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023 * in the United States and other countries.]
024 *
025 * ------------
026 * $Id: WeakReferenceList.java,v 1.11 2007/04/01 18:49:34 taqua Exp $
027 * ------------
028 * (C) Copyright 2000-2005, by Object Refinery Limited.
029 * (C) Copyright 2005-2007, by Pentaho Corporation.
030 */
031
032 package org.jfree.report.util;
033
034 import java.io.IOException;
035 import java.io.Serializable;
036 import java.lang.ref.Reference;
037 import java.lang.ref.WeakReference;
038
039 /**
040 * The WeakReference list uses <code>java.lang.ref.WeakReference</code>s to store its
041 * contents. In contrast to the WeakHashtable, this list knows how to restore missing
042 * content, so that garbage collected elements can be restored when they are accessed.
043 * <p/>
044 * By default this list can contain 25 elements, where the first element is stored using a
045 * strong reference, which is not garbage collected.
046 * <p/>
047 * Restoring the elements is not implemented, concrete implementations will have to
048 * override the <code>restoreChild(int)</code> method. The <code>getMaxChildCount</code>
049 * method defines the maxmimum number of children in the list. When more than
050 * <code>maxChildCount</code> elements are contained in this list, add will always return
051 * false to indicate that adding the element failed.
052 * <p/>
053 * To customize the list, override createReference to create a different kind of
054 * reference.
055 * <p/>
056 * This list is able to add or clearFromParent elements, but inserting or removing of elements is
057 * not possible.
058 * <p/>
059 *
060 * @author Thomas Morgner
061 */
062 public abstract class WeakReferenceList implements Serializable, Cloneable
063 {
064 /**
065 * The master element.
066 */
067 private Object master;
068
069 /**
070 * Storage for the references.
071 */
072 private Reference[] childs;
073
074 /**
075 * The current number of elements.
076 */
077 private int size;
078
079 /**
080 * The maximum number of elements.
081 */
082 private final int maxChilds;
083
084 /**
085 * Creates a new weak reference list. The storage of the list is limited to
086 * getMaxChildCount() elements.
087 *
088 * @param maxChildCount the maximum number of elements.
089 */
090 protected WeakReferenceList (final int maxChildCount)
091 {
092 this.maxChilds = maxChildCount;
093 this.childs = new Reference[maxChildCount - 1];
094 }
095
096 /**
097 * Returns the maximum number of children in this list.
098 *
099 * @return the maximum number of elements in this list.
100 */
101 protected final int getMaxChildCount ()
102 {
103 return maxChilds;
104 }
105
106 /**
107 * Returns the master element of this list. The master element is the element stored by
108 * a strong reference and cannot be garbage collected.
109 *
110 * @return the master element
111 */
112 protected Object getMaster ()
113 {
114 return master;
115 }
116
117 /**
118 * Attempts to restore the child stored on the given index.
119 *
120 * @param index the index.
121 * @return null if the child could not be restored or the restored child.
122 */
123 protected abstract Object restoreChild (int index);
124
125 /**
126 * Returns the child stored at the given index. If the child has been garbage collected,
127 * it gets restored using the restoreChild function.
128 *
129 * @param index the index.
130 * @return the object.
131 */
132 public Object get (final int index)
133 {
134 if (isMaster(index))
135 {
136 return master;
137 }
138 else
139 {
140 final Reference ref = childs[getChildPos(index)];
141 if (ref == null)
142 {
143 throw new IllegalStateException("State: " + index);
144 }
145 Object ob = ref.get();
146 if (ob == null)
147 {
148 ob = restoreChild(index);
149 childs[getChildPos(index)] = createReference(ob);
150 }
151 return ob;
152 }
153 }
154
155 /**
156 * Replaces the child stored at the given index with the new child which can be null.
157 *
158 * @param report the object.
159 * @param index the index.
160 */
161 public void set (final Object report, final int index)
162 {
163 if (isMaster(index))
164 {
165 master = report;
166 }
167 else
168 {
169 childs[getChildPos(index)] = createReference(report);
170 }
171 }
172
173 /**
174 * Creates a new reference for the given object.
175 *
176 * @param o the object.
177 * @return a WeakReference for the object o without any ReferenceQueue attached.
178 */
179 private Reference createReference (final Object o)
180 {
181 return new WeakReference(o);
182 }
183
184 /**
185 * Adds the element to the list. If the maximum size of the list is exceeded, this
186 * function returns false to indicate that adding failed.
187 *
188 * @param rs the object.
189 * @return true, if the object was successfully added to the list, false otherwise
190 */
191 public boolean add (final Object rs)
192 {
193 if (size == 0)
194 {
195 master = rs;
196 size = 1;
197 return true;
198 }
199 else
200 {
201 if (size < getMaxChildCount())
202 {
203 childs[size - 1] = createReference(rs);
204 size++;
205 return true;
206 }
207 else
208 {
209 // was not able to add this to this list, maximum number of entries reached.
210 return false;
211 }
212 }
213 }
214
215 /**
216 * Returns true, if the given index denotes a master index of this list.
217 *
218 * @param index the index.
219 * @return true if the index is a master index.
220 */
221 protected boolean isMaster (final int index)
222 {
223 return index % getMaxChildCount() == 0;
224 }
225
226 /**
227 * Returns the internal storage position for the child.
228 *
229 * @param index the index.
230 * @return the internal storage index.
231 */
232 protected int getChildPos (final int index)
233 {
234 return index % getMaxChildCount() - 1;
235 }
236
237 /**
238 * Returns the size of the list.
239 *
240 * @return the size.
241 */
242 public int getSize ()
243 {
244 return size;
245 }
246
247 /**
248 * Serialisation support. The transient child elements are not saved.
249 *
250 * @param out the output stream.
251 * @throws IOException if there is an I/O error.
252 */
253 private void writeObject (final java.io.ObjectOutputStream out)
254 throws IOException
255 {
256 final Reference[] orgChilds = childs;
257 try
258 {
259 childs = null;
260 out.defaultWriteObject();
261 }
262 finally
263 {
264 childs = orgChilds;
265 }
266 }
267
268 /**
269 * Serialisation support. The transient child elements were not saved.
270 *
271 * @param in the input stream.
272 * @throws IOException if there is an I/O error.
273 * @throws ClassNotFoundException if a serialized class is not defined on this system.
274 */
275 private void readObject (final java.io.ObjectInputStream in)
276 throws IOException, ClassNotFoundException
277 {
278 in.defaultReadObject();
279 childs = new Reference[getMaxChildCount() - 1];
280 for (int i = 0; i < childs.length; i++)
281 {
282 childs[i] = createReference(null);
283 }
284 }
285
286 /**
287 * Creates and returns a copy of this object. The precise meaning of "copy" may depend
288 * on the class of the object. The general intent is that, for any object <tt>x</tt>,
289 * the expression: <blockquote>
290 * <pre>
291 * x.clone() != x</pre></blockquote>
292 * will be true, and that the expression: <blockquote>
293 * <pre>
294 * x.clone().getClass() == x.getClass()</pre></blockquote>
295 * will be <tt>true</tt>, but these are not absolute requirements. While it is typically
296 * the case that: <blockquote>
297 * <pre>
298 * x.clone().equals(x)</pre></blockquote>
299 * will be <tt>true</tt>, this is not an absolute requirement.
300 * <p/>
301 * By convention, the returned object should be obtained by calling
302 * <tt>super.clone</tt>. If a class and all of its superclasses (except
303 * <tt>Object</tt>) obey this convention, it will be the case that
304 * <tt>x.clone().getClass() == x.getClass()</tt>.
305 * <p/>
306 * By convention, the object returned by this method should be independent of this
307 * object (which is being cloned). To achieve this independence, it may be necessary to
308 * modify one or more fields of the object returned by <tt>super.clone</tt> before
309 * returning it. Typically, this means copying any mutable objects that comprise the
310 * internal "deep structure" of the object being cloned and replacing the references to
311 * these objects with references to the copies. If a class contains only primitive
312 * fields or references to immutable objects, then it is usually the case that no fields
313 * in the object returned by <tt>super.clone</tt> need to be modified.
314 * <p/>
315 * The method <tt>clone</tt> for class <tt>Object</tt> performs a specific cloning
316 * operation. First, if the class of this object does not implement the interface
317 * <tt>Cloneable</tt>, then a <tt>CloneNotSupportedException</tt> is thrown. Note that
318 * all arrays are considered to implement the interface <tt>Cloneable</tt>. Otherwise,
319 * this method creates a new instance of the class of this object and initializes all
320 * its fields with exactly the contents of the corresponding fields of this object, as
321 * if by assignment; the contents of the fields are not themselves cloned. Thus, this
322 * method performs a "shallow copy" of this object, not a "deep copy" operation.
323 * <p/>
324 * The class <tt>Object</tt> does not itself implement the interface <tt>Cloneable</tt>,
325 * so calling the <tt>clone</tt> method on an object whose class is <tt>Object</tt> will
326 * result in throwing an exception at run time.
327 *
328 * @return a clone of this instance.
329 *
330 * @throws CloneNotSupportedException if the object's class does not support the
331 * <code>Cloneable</code> interface. Subclasses that
332 * override the <code>clone</code> method can also
333 * throw this exception to indicate that an instance
334 * cannot be cloned.
335 * @see Cloneable
336 */
337 protected Object clone ()
338 throws CloneNotSupportedException
339 {
340 final WeakReferenceList list = (WeakReferenceList) super.clone();
341 list.childs = (Reference[]) childs.clone();
342 return list;
343 }
344 }