/* * org.openmicroscopy.shoola.util.mem.Handle * *------------------------------------------------------------------------------ * Copyright (C) 2006 University of Dundee. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.util.mem; //Java imports //Third-party libraries //Application-internal dependencies /** * Provides the basic machinery to share the same logical state across objects * with different identities. * <p>This class calls for a distinction between object identity and object * state. Made this distinction, it becomes possible to share the same state * across different objects upon copy operations. When an object is updated, * a new state representation is bound to that object, while the other objects * can still share the previous state. This way we can have shallow copy with * the semantics of deep copy. This can result in dramatically reduced memory * footprint when:</p> * <ul> * <li>A considerable amount of copies of a given master object are * needed.</li> * <li>You can't use references to the master object, because the copied * objects need to have their own identity.</li> * <li>The number of copied objects that are going to change their state * after the copy operation is small compared to the total number of * copies.</li> * </ul> * <p>For example, think of a class <code>R</code> that represents a rectangle * in the plane with <code>4</code> integer fields <code>x, y, w, h</code>, and * say you want to use instances of this class to describe an ROI (region of * interest) selection in a given image 3D-stack composed of <code>100</code> * planes — each plane would contain a rectangle selection and all those * selections would make up your ROI. Let's assume that the initial selection * is a discrete 3D-rectangle that spans all planes in the stack — you * would have one rectangle per plane, every rectangle would have exactly the * same state, say <code>s[x=0, y=0, w=3, h=4]</code>. Moreover, let's assume * that you will have to modify slightly this initial ROI in order to get the * final selection — for example by resizing/moving a couple of rectangles * within the selection. Now, when you start off with the initial selection, * you could decide to clone an initial master object whose state is * <code>s</code> — this way, you can later modify one of the copies * without affecting the others. However, because <i>Java</i> makes no * distinction between object identity and state, you would have in memory * <code>100</code> references and <code>100</code> copies of the same logical * state <code>s</code>, while you actually only need one.<p> * <p>The purpose of this class is to help you save memory in situations like * that just described by approximating the semantics of the well known * Handle/Body and Counted Body idioms often found in <i>C++</i> programs. A * given class abstraction is implemented by two actual classes which replicate * the same class interface. One class, the Handle, takes on the role of an * object identifier and forwards all calls to the other class, the Body, which * implements the actual functionality. Clients can only access instances of * the Handle which can all share the same Body object whenever appropriate.</p> * <p>The way this works in our case is pretty easy. An Handle class extends * this base <code>Handle</code> class and provides a reference to an instance * of the corresponding Body class. The concrete Handle class exposes the same * interface as its corresponding Body (this is not an absolute requirement, but * usually an implementation trade-off) and has <i>no state</i> — in fact, * the state is hold by the associated Body object. The Handle just forwards to * the Body any call that only reads the Body's state. However, it must call * the {@link #breakSharing() breakSharing} protected method <i>before</i> * forwarding any call that modifies the Body's state. It is crucial that * concrete <code>Handle</code> classes stick to this rule. In fact, the * {@link #copy() copy} method simply rebinds a new <code>Handle</code> to the * existing Body, so subclasses must notify any incumbent change to the Body's * state for the <code>Handle</code> to break state sharing. Lastly, it's also * fundamental that the Body class implements the {@link Copiable} interface * correctly for all this to work properly.</p> * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author <br>Andrea Falconi      * <a href="mailto:a.falconi@dundee.ac.uk"> * a.falconi@dundee.ac.uk</a> * @version 2.2 * <small> * (<b>Internal version:</b> $Revision$ $Date$) * </small> * @since OME2.2 */ public abstract class Handle implements Copiable, Cloneable { /** Reference to the Body object. */ private Copiable body; /** * Tells whether the {@link #body} is referenced by other * <code>Handle</code> objects. */ private boolean shared; /** * Subclasses use this constructor to specify the Body instance this * handle will be paired up with. * Subclasses must pass in a <i>newly</i> created object. * * @param body Reference to the Body object. Mustn't be <code>null</code>. */ protected Handle(Copiable body) { if (body == null) throw new NullPointerException("No body."); this.body = body; shared = false; } /** * Returns a reference to the Body object that is <i>currently</i> paired * up with this handle. * The type of the returned object is the same as the one of the object * that was passed to this class' protected constructor. However, the * object returned by this method could be different from the one initially * passed in at creation time if the {@link #breakSharing() breakSharing} * method has been invoked. For this reason, subclasses mustn't cache a * reference to the object returned by this method. * Moreover, subclasses must never leak out a reference to the returned * Body object. * * @return The Body object. */ protected Object getBody() { return body; } /** * Subclasses must call this method <i>before</i> forwarding any call * that modifies the Body's state. */ protected final void breakSharing() { if (shared) { body = (Copiable) body.copy(); shared = false; } } /** * Returns a deep copy of this object. * To be precise, this method returns an object that will behave like * a deep copy, but has a negligible memory footprint until an attempt * to change its state is made. Then the whole original state is restored * in memory so that the state change operation can take place. * * @return A deep copy of this object. The class of the returned object * is the same as the class of this object. */ public final Object copy() { Handle h; //Make a shallow copy of this object. This is fine b/c subclasses //are not supposed to hold any state, never mind references to other //objects :) try { h = (Handle) clone(); //Class of h is this instance's class. } catch (CloneNotSupportedException cnse) { //Shouldn't happen as this class implements Cloneable. throw new InternalError( "JVM Internal Error: couldn't clone object that "+ "implements Cloneable."); } h.body = this.body; //Not actually needed, added for clarity. //Set state sharing flag. h.shared = true; this.shared = true; return h; } }