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 3048 2007-07-28 18:02:42Z tmorgner $
027: * ------------
028: * (C) Copyright 2000-2005, by Object Refinery Limited.
029: * (C) Copyright 2005-2007, by Pentaho Corporation.
030: */package org.jfree.report.util;
031:
032: import java.io.IOException;
033: import java.io.Serializable;
034: import java.lang.ref.Reference;
035: import java.lang.ref.WeakReference;
036:
037: /**
038: * The WeakReference list uses <code>java.lang.ref.WeakReference</code>s to store its
039: * contents. In contrast to the WeakHashtable, this list knows how to restore missing
040: * content, so that garbage collected elements can be restored when they are accessed.
041: * <p/>
042: * By default this list can contain 25 elements, where the first element is stored using a
043: * strong reference, which is not garbage collected.
044: * <p/>
045: * Restoring the elements is not implemented, concrete implementations will have to
046: * override the <code>restoreChild(int)</code> method. The <code>getMaxChildCount</code>
047: * method defines the maxmimum number of children in the list. When more than
048: * <code>maxChildCount</code> elements are contained in this list, add will always return
049: * false to indicate that adding the element failed.
050: * <p/>
051: * To customize the list, override createReference to create a different kind of
052: * reference.
053: * <p/>
054: * This list is able to add or clearFromParent elements, but inserting or removing of elements is
055: * not possible.
056: * <p/>
057: *
058: * @author Thomas Morgner
059: */
060: public abstract class WeakReferenceList implements Serializable,
061: Cloneable {
062: /**
063: * The master element.
064: */
065: private Object master;
066:
067: /**
068: * Storage for the references.
069: */
070: private Reference[] childs;
071:
072: /**
073: * The current number of elements.
074: */
075: private int size;
076:
077: /**
078: * The maximum number of elements.
079: */
080: private final int maxChilds;
081:
082: /**
083: * Creates a new weak reference list. The storage of the list is limited to
084: * getMaxChildCount() elements.
085: *
086: * @param maxChildCount the maximum number of elements.
087: */
088: protected WeakReferenceList(final int maxChildCount) {
089: this .maxChilds = maxChildCount;
090: this .childs = new Reference[maxChildCount - 1];
091: }
092:
093: /**
094: * Returns the maximum number of children in this list.
095: *
096: * @return the maximum number of elements in this list.
097: */
098: protected final int getMaxChildCount() {
099: return maxChilds;
100: }
101:
102: /**
103: * Returns the master element of this list. The master element is the element stored by
104: * a strong reference and cannot be garbage collected.
105: *
106: * @return the master element
107: */
108: protected Object getMaster() {
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,
122: * it gets restored using the restoreChild function.
123: *
124: * @param index the index.
125: * @return the object.
126: */
127: public Object get(final int index) {
128: if (isMaster(index)) {
129: return master;
130: } else {
131: final Reference ref = childs[getChildPos(index)];
132: if (ref == null) {
133: throw new IllegalStateException("State: " + index);
134: }
135: Object ob = ref.get();
136: if (ob == null) {
137: ob = restoreChild(index);
138: childs[getChildPos(index)] = createReference(ob);
139: }
140: return ob;
141: }
142: }
143:
144: /**
145: * Replaces the child stored at the given index with the new child which can be null.
146: *
147: * @param report the object.
148: * @param index the index.
149: */
150: public void set(final Object report, final int index) {
151: if (isMaster(index)) {
152: master = report;
153: } else {
154: childs[getChildPos(index)] = createReference(report);
155: }
156: }
157:
158: /**
159: * Creates a new reference for the given object.
160: *
161: * @param o the object.
162: * @return a WeakReference for the object o without any ReferenceQueue attached.
163: */
164: private Reference createReference(final Object o) {
165: return new WeakReference(o);
166: }
167:
168: /**
169: * Adds the element to the list. If the maximum size of the list is exceeded, this
170: * function returns false to indicate that adding failed.
171: *
172: * @param rs the object.
173: * @return true, if the object was successfully added to the list, false otherwise
174: */
175: public boolean add(final Object rs) {
176: if (size == 0) {
177: master = rs;
178: size = 1;
179: return true;
180: } else {
181: if (size < getMaxChildCount()) {
182: childs[size - 1] = createReference(rs);
183: size++;
184: return true;
185: } else {
186: // was not able to add this to this list, maximum number of entries reached.
187: return false;
188: }
189: }
190: }
191:
192: /**
193: * Returns true, if the given index denotes a master index of this list.
194: *
195: * @param index the index.
196: * @return true if the index is a master index.
197: */
198: protected boolean isMaster(final int index) {
199: return index % getMaxChildCount() == 0;
200: }
201:
202: /**
203: * Returns the internal storage position for the child.
204: *
205: * @param index the index.
206: * @return the internal storage index.
207: */
208: protected int getChildPos(final int index) {
209: return index % getMaxChildCount() - 1;
210: }
211:
212: /**
213: * Returns the size of the list.
214: *
215: * @return the size.
216: */
217: public int getSize() {
218: return size;
219: }
220:
221: /**
222: * Serialisation support. The transient child elements are not saved.
223: *
224: * @param out the output stream.
225: * @throws IOException if there is an I/O error.
226: */
227: private void writeObject(final java.io.ObjectOutputStream out)
228: throws IOException {
229: final Reference[] orgChilds = childs;
230: try {
231: childs = null;
232: out.defaultWriteObject();
233: } finally {
234: childs = orgChilds;
235: }
236: }
237:
238: /**
239: * Serialisation support. The transient child elements were not saved.
240: *
241: * @param in the input stream.
242: * @throws IOException if there is an I/O error.
243: * @throws ClassNotFoundException if a serialized class is not defined on this system.
244: */
245: private void readObject(final java.io.ObjectInputStream in)
246: throws IOException, ClassNotFoundException {
247: in.defaultReadObject();
248: childs = new Reference[getMaxChildCount() - 1];
249: for (int i = 0; i < childs.length; i++) {
250: childs[i] = createReference(null);
251: }
252: }
253:
254: /**
255: * Creates and returns a copy of this object. The precise meaning of "copy" may depend
256: * on the class of the object. The general intent is that, for any object <tt>x</tt>,
257: * the expression: <blockquote>
258: * <pre>
259: * x.clone() != x</pre></blockquote>
260: * will be true, and that the expression: <blockquote>
261: * <pre>
262: * x.clone().getClass() == x.getClass()</pre></blockquote>
263: * will be <tt>true</tt>, but these are not absolute requirements. While it is typically
264: * the case that: <blockquote>
265: * <pre>
266: * x.clone().equals(x)</pre></blockquote>
267: * will be <tt>true</tt>, this is not an absolute requirement.
268: * <p/>
269: * By convention, the returned object should be obtained by calling
270: * <tt>super.clone</tt>. If a class and all of its superclasses (except
271: * <tt>Object</tt>) obey this convention, it will be the case that
272: * <tt>x.clone().getClass() == x.getClass()</tt>.
273: * <p/>
274: * By convention, the object returned by this method should be independent of this
275: * object (which is being cloned). To achieve this independence, it may be necessary to
276: * modify one or more fields of the object returned by <tt>super.clone</tt> before
277: * returning it. Typically, this means copying any mutable objects that comprise the
278: * internal "deep structure" of the object being cloned and replacing the references to
279: * these objects with references to the copies. If a class contains only primitive
280: * fields or references to immutable objects, then it is usually the case that no fields
281: * in the object returned by <tt>super.clone</tt> need to be modified.
282: * <p/>
283: * The method <tt>clone</tt> for class <tt>Object</tt> performs a specific cloning
284: * operation. First, if the class of this object does not implement the interface
285: * <tt>Cloneable</tt>, then a <tt>CloneNotSupportedException</tt> is thrown. Note that
286: * all arrays are considered to implement the interface <tt>Cloneable</tt>. Otherwise,
287: * this method creates a new instance of the class of this object and initializes all
288: * its fields with exactly the contents of the corresponding fields of this object, as
289: * if by assignment; the contents of the fields are not themselves cloned. Thus, this
290: * method performs a "shallow copy" of this object, not a "deep copy" operation.
291: * <p/>
292: * The class <tt>Object</tt> does not itself implement the interface <tt>Cloneable</tt>,
293: * so calling the <tt>clone</tt> method on an object whose class is <tt>Object</tt> will
294: * result in throwing an exception at run time.
295: *
296: * @return a clone of this instance.
297: *
298: * @throws CloneNotSupportedException if the object's class does not support the
299: * <code>Cloneable</code> interface. Subclasses that
300: * override the <code>clone</code> method can also
301: * throw this exception to indicate that an instance
302: * cannot be cloned.
303: * @see Cloneable
304: */
305: protected Object clone() throws CloneNotSupportedException {
306: final WeakReferenceList list = (WeakReferenceList) super
307: .clone();
308: list.childs = (Reference[]) childs.clone();
309: return list;
310: }
311: }
|