001package votorola.g.hold; // Copyright 2005-2007, Michael Allan.  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE.
002
003import votorola.g.lang.*;
004
005
006/** An unwindable spool of {@linkplain Hold holds}.  It contols and implements the closure
007  * of an object - the "unwinding" of its state.  As an object takes hold of resources
008  * that later need to be released, it constructs a {@linkplain Hold Hold} for each, and
009  * winds it onto a spool.  At closure the object, the spool is unwound, and each hold is
010  * {@linkplain Hold#release() released}.
011  *
012  * <p>An example is listener registration. This is state that often needs to be unwound,
013  * in order to prevent memory leaks.  Using a spool, both registration and unregistration
014  * may be coded together in line. For example:</p>
015  *
016  * <blockquote><pre>
017  *     registry.addListener( C.this );
018  *     spool.add( new Hold()
019  *     {
020  *         public void release() { registry.removeListener( C.this ); }
021  *     });
022  *     </pre></blockquote>
023  *
024  * <p>The life cycle of spools follows two common patterns.  In one, a spool is created
025  * internally by the object, and later unwound by it (in a public close() method, for
026  * example) In the other pattern, a spool is passed to the object by a construction
027  * parameter, and later unwound by its creator (effectively destroying the object, and
028  * any others that had wound themselves onto it).  The latter is the more common pattern;
029  * but the codebase [of textbender] has examples of both.  In any case, once unwound, a
030  * spool is never resused.</p>
031  */
032public interface Spool
033{
034
035
036    /** A common instance of a null catcher.
037      */
038    public static final Catcher0R<Hold> CATCHER_0 = Catcher0R.i(); // till we figure out how to declare Catcher0R.i() so we can use a direct reference instead
039
040
041
042   // - S p o o l ------------------------------------------------------------------------
043
044
045    /** Adds the hold to the spool or releases it immediately.  If the spool is unwinding
046      * then the hold is released immediately, otherwise it is added.
047      *
048      *     @throws IllegalStateException if this contract cannot be met (e.g. if the
049      *       spool runs out of space, and no other unchecked exception applies).
050      *
051      *     @return true if the hold is added; false if it is released instead.
052      */
053    public boolean add( Hold hold );
054
055
056
057    /** Returns true if the spool is {@linkplain #unwind() unwinding} or already unwound.
058      * Once true, it never reverts to false.
059      */
060    public boolean isUnwinding();
061
062
063
064    /** Commences to unwind this spool.  Equivalent to {@linkplain #unwind(Catcher)
065      * unwind}(CATCHER_0).
066      *
067      *     @return true if unwinding commences with this call; false if it had already
068      *       commenced.
069      */
070    public boolean unwind();
071
072
073
074    /** Commences to unwind this spool, removing and releasing each of its holds.  Works
075      * in LIFO order. Once unwinding is commenced, subsequent calls to this method have
076      * no effect.
077      *
078      *     @param catcher the catcher for any errors or exceptions that occur during
079      *       unwinding.
080      *
081      *     @return true if unwinding commences with this call; false if it had already
082      *       commenced.
083      */
084    public boolean unwind( Catcher<Hold> catcher );
085
086
087
088}