1 /**
2 * =========================================================
3 * Pentaho-Reporting-Classic : a free Java reporting library
4 * =========================================================
5 *
6 * Project Info: http://reporting.pentaho.org/
7 *
8 * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
9 *
10 * This library is free software; you can redistribute it and/or modify it under the terms
11 * of the GNU Lesser General Public License as published by the Free Software Foundation;
12 * either version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License along with this
19 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
23 * in the United States and other countries.]
24 *
25 * ------------
26 * WeakReferenceList.java
27 * ------------
28 * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
29 */
30
31 package org.jfree.report.util;
32
33 import java.io.IOException;
34 import java.io.ObjectInputStream;
35 import java.io.Serializable;
36 import java.lang.ref.Reference;
37 import java.lang.ref.WeakReference;
38
39 /**
40 * The WeakReference list uses <code>java.lang.ref.WeakReference</code>s to store its contents. In contrast to the
41 * WeakHashtable, this list knows how to restore missing content, so that garbage collected elements can be restored
42 * when they are accessed.
43 * <p/>
44 * By default this list can contain 25 elements, where the first element is stored using a strong reference, which is
45 * not garbage collected.
46 * <p/>
47 * Restoring the elements is not implemented, concrete implementations will have to override the
48 * <code>restoreChild(int)</code> method. The <code>getMaxChildCount</code> method defines the maxmimum number of
49 * children in the list. When more than <code>maxChildCount</code> elements are contained in this list, add will always
50 * return false to indicate that adding the element failed.
51 * <p/>
52 * To customize the list, override createReference to create a different kind of reference.
53 * <p/>
54 * This list is able to add or replace elements, but inserting or removing of elements is not possible.
55 *
56 * @author Thomas Morgner
57 */
58 public abstract class WeakReferenceList implements Serializable, Cloneable
59 {
60 /**
61 * The master element.
62 */
63 private Object master;
64
65 /**
66 * Storage for the references.
67 */
68 private transient Reference[] childs;
69
70 /**
71 * The current number of elements.
72 */
73 private int size;
74
75 /**
76 * The maximum number of elements.
77 */
78 private final int maxChilds;
79
80 /**
81 * Creates a new weak reference list. The storage of the list is limited to getMaxChildCount() elements.
82 *
83 * @param maxChildCount the maximum number of elements.
84 */
85 protected WeakReferenceList(final int maxChildCount)
86 {
87 this.maxChilds = maxChildCount;
88 this.childs = new Reference[maxChildCount - 1];
89 }
90
91 /**
92 * Returns the maximum number of children in this list.
93 *
94 * @return the maximum number of elements in this list.
95 */
96 protected final int getMaxChildCount()
97 {
98 return maxChilds;
99 }
100
101 /**
102 * Returns the master element of this list. The master element is the element stored by a strong reference and cannot
103 * be garbage collected.
104 *
105 * @return the master element
106 */
107 protected Object getMaster()
108 {
109 return master;
110 }
111
112 /**
113 * Attempts to restore the child stored on the given index.
114 *
115 * @param index the index.
116 * @return null if the child could not be restored or the restored child.
117 */
118 protected abstract Object restoreChild(int index);
119
120 /**
121 * Returns the child stored at the given index. If the child has been garbage collected, it gets restored using the
122 * restoreChild function.
123 *
124 * @param index the index.
125 * @return the object.
126 */
127 public Object get(final int index)
128 {
129 if (isMaster(index))
130 {
131 return master;
132 }
133 else
134 {
135 final Reference ref = childs[getChildPos(index)];
136 if (ref == null)
137 {
138 throw new IllegalStateException("State: " + index);
139 }
140 Object ob = ref.get();
141 if (ob == null)
142 {
143 ob = restoreChild(index);
144 childs[getChildPos(index)] = createReference(ob);
145 }
146 return ob;
147 }
148 }
149
150 /**
151 * Replaces the child stored at the given index with the new child which can be null.
152 *
153 * @param report the object.
154 * @param index the index.
155 */
156 public void set(final Object report, final int index)
157 {
158 if (isMaster(index))
159 {
160 master = report;
161 }
162 else
163 {
164 childs[getChildPos(index)] = createReference(report);
165 }
166 }
167
168 /**
169 * Creates a new reference for the given object.
170 *
171 * @param o the object.
172 * @return a WeakReference for the object o without any ReferenceQueue attached.
173 */
174 private Reference createReference(final Object o)
175 {
176 return new WeakReference(o);
177 }
178
179 /**
180 * Adds the element to the list. If the maximum size of the list is exceeded, this function returns false to indicate
181 * that adding failed.
182 *
183 * @param rs the object.
184 * @return true, if the object was successfully added to the list, false otherwise
185 */
186 public boolean add(final Object rs)
187 {
188 if (size == 0)
189 {
190 master = rs;
191 size = 1;
192 return true;
193 }
194 else
195 {
196 if (size < getMaxChildCount())
197 {
198 childs[size - 1] = createReference(rs);
199 size++;
200 return true;
201 }
202 else
203 {
204 // was not able to add this to this list, maximum number of entries reached.
205 return false;
206 }
207 }
208 }
209
210 /**
211 * Returns true, if the given index denotes a master index of this list.
212 *
213 * @param index the index.
214 * @return true if the index is a master index.
215 */
216 protected boolean isMaster(final int index)
217 {
218 return index % getMaxChildCount() == 0;
219 }
220
221 /**
222 * Returns the internal storage position for the child.
223 *
224 * @param index the index.
225 * @return the internal storage index.
226 */
227 protected int getChildPos(final int index)
228 {
229 return index % getMaxChildCount() - 1;
230 }
231
232 /**
233 * Returns the size of the list.
234 *
235 * @return the size.
236 */
237 public int getSize()
238 {
239 return size;
240 }
241
242 /**
243 * Serialisation support. The transient child elements were not saved.
244 *
245 * @param in the input stream.
246 * @throws IOException if there is an I/O error.
247 * @throws ClassNotFoundException if a serialized class is not defined on this system.
248 */
249 private void readObject(final ObjectInputStream in)
250 throws IOException, ClassNotFoundException
251 {
252 in.defaultReadObject();
253 childs = new Reference[getMaxChildCount() - 1];
254 for (int i = 0; i < childs.length; i++)
255 {
256 childs[i] = createReference(null);
257 }
258 }
259
260 /**
261 * Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
262 * The general intent is that, for any object <tt>x</tt>, the expression: <blockquote>
263 * <pre>
264 * x.clone() != x</pre></blockquote>
265 * will be true, and that the expression: <blockquote>
266 * <pre>
267 * x.clone().getClass() == x.getClass()</pre></blockquote>
268 * will be <tt>true</tt>, but these are not absolute requirements. While it is typically the case that: <blockquote>
269 * <pre>
270 * x.clone().equals(x)</pre></blockquote>
271 * will be <tt>true</tt>, this is not an absolute requirement.
272 * <p/>
273 * By convention, the returned object should be obtained by calling <tt>super.clone</tt>. If a class and all of its
274 * superclasses (except <tt>Object</tt>) obey this convention, it will be the case that <tt>x.clone().getClass() ==
275 * x.getClass()</tt>.
276 * <p/>
277 * By convention, the object returned by this method should be independent of this object (which is being cloned). To
278 * achieve this independence, it may be necessary to modify one or more fields of the object returned by
279 * <tt>super.clone</tt> before returning it. Typically, this means copying any mutable objects that comprise the
280 * internal "deep structure" of the object being cloned and replacing the references to these objects with references
281 * to the copies. If a class contains only primitive fields or references to immutable objects, then it is usually
282 * the case that no fields in the object returned by <tt>super.clone</tt> need to be modified.
283 * <p/>
284 * The method <tt>clone</tt> for class <tt>Object</tt> performs a specific cloning operation. First, if the class of
285 * this object does not implement the interface <tt>Cloneable</tt>, then a <tt>CloneNotSupportedException</tt> is
286 * thrown. Note that all arrays are considered to implement the interface <tt>Cloneable</tt>. Otherwise, this method
287 * creates a new instance of the class of this object and initializes all its fields with exactly the contents of the
288 * corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned.
289 * Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.
290 * <p/>
291 * The class <tt>Object</tt> does not itself implement the interface <tt>Cloneable</tt>, so calling the <tt>clone</tt>
292 * method on an object whose class is <tt>Object</tt> will result in throwing an exception at run time.
293 *
294 * @return a clone of this instance.
295 * @throws CloneNotSupportedException if the object's class does not support the <code>Cloneable</code> interface.
296 * Subclasses that override the <code>clone</code> method can also throw this
297 * exception to indicate that an instance cannot be cloned.
298 * @see Cloneable
299 */
300 protected Object clone()
301 throws CloneNotSupportedException
302 {
303 final WeakReferenceList list = (WeakReferenceList) super.clone();
304 list.childs = (Reference[]) childs.clone();
305 return list;
306 }
307 }