Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

dk.rode.thesis.templatemethod
Class SequenceTemplate<K,E>

java.lang.Object
  extended by dk.rode.thesis.meta.model.AbstractSequence<E>
      extended by dk.rode.thesis.templatemethod.SequenceTemplate<K,E>
Type Parameters:
K - The type of correlation keys used by this sequence. Use Void if not used.
E - The type of values delivered by this sequence.
All Implemented Interfaces:
Sequence<E>, Copyable<Sequence<E>>, StrictCopyable<Sequence<E>>, Stringable<Sequence<E>>, Closeable
Direct Known Subclasses:
FileSequence, NegativeSequence, ZipSequence

@Participant(value="AbstractClass")
public abstract class SequenceTemplate<K,E>
extends AbstractSequence<E>
implements Closeable

A sequence template forms a template for sequences requiring several steps to construct, deliver, and dispose sequence values. An example could be values fetched from a database that requires steps like open connection, begin transaction, fetch value, end transaction, and close connection.

Sub-class implementation:
The basic sequence methods current(), next(), and reset() as well as close() are declared final - they are template methods. Instead, a sequence template defines the following (abstract) primitive operations that can or must be implemented, i.e. if abstract, in sub-class implementations:

In pseudo-code, when delivering the next sequence value, the functionality of a sequence template is thus:
   // current = old value
   E current = this.current();
   
   // Open and get correlation key...
   K key = nextValueOpen(current);
   
   // Get actual value based on correlation key and *old* value...
   value = nextValue(key, current);
   
   // Close newly created value (e.g. resources)...
   nextValueClose(key, value);
   
   // Update current...
   this.current = value;
   return value;
 
As default, sequence templates are declared as bounded, consistent, and unique, but sub-classes should override this behaviour as appropriate.

Implementation notes:
All attributes are declared private in this class to prevent sub-classes from modifying them outside the scope of the (abstract) operations.

Java makes it easy for sub-classes to determine which (abstract) operations must be implemented: those declared abstract. Furthermore, to ensure that the template methods are not overridden, they should be declared final. This also gives the sub-class implementer a clear view of which methods can be overridden. Gamma et al. also emphasise the need for consistent naming among (abstract) operations for clarity [Gamma95, p.329]. Here, all operations related to overall sequence functionality are prefixed with sequence, and operations related to generating the next value with nextValue. The last part of the names of the (abstract) operations determine their functionality, e.g. Open and Close as in nextValueOpen and nextValueClose.

As described above, the initialisation of sub-class sequence implementations is performed using the sequenceOpen(Object...) method, invoked automatically via the constructors defined in this class when needed. Sub-class constructors must invoke one of these constructors, but will declare explicit arguments types as needed to create the specific type of sequence. They will thus pass matching arguments to the super-constructor, which then invokes the sequenceOpen(Object...) initialisation method. However, casts are still required in the method implementation, but are known to succeed since the arguments originate from one of the parameter type-safe constructors in the same class. This is in our view a very elegant use of varargs. An alternative could be to use an additional generic type parameter on this class, say P, to narrow the argument type(s) for the constructors and the sequenceOpen(Object...) method (and thus in sub-classes overriding it) even further, e.g. sequenceOpen(P...). But, if more than one argument is needed with different type hierarchies, the actual type parameter for P would still need to be Object, so the question is how much will be gained?! Here, no such type parameter is used.

Author:
Gunni Rode / rode.dk

Nested Class Summary
 
Nested classes/interfaces inherited from interface dk.rode.thesis.meta.model.Sequence
Sequence.State
 
Field Summary
private  boolean closed
          True if this sequence has been closed.
private  E current
          The current sequence value.
private  int index
          The current index into this sequence, used to calculate the size of this sequence.
protected static SequencePolicy POLICY
          Policy use for logging of this sequence.
private  int size
          The size of this sequence, i.e. the number of values delivered.
 
Fields inherited from class dk.rode.thesis.meta.model.AbstractSequence
state
 
Constructor Summary
protected SequenceTemplate(Object... arguments)
          Constructor, which creates this sequence template.
protected SequenceTemplate(SequenceTemplate<K,E> sequence, Object... arguments)
          Copy constructor, which creates this sequence template based on sequence, i.e. to have the same size, use the same current index, etc.
 
Method Summary
 boolean bounded()
          Returns true if this sequence is bounded, i.e.
 void close()
          Closes this sequence.
 boolean consistent()
          Returns true if this sequence is consistent, i.e. deliver the same values, in order, after restart or reset.
 E current()
          Returns the current element from this sequence.
protected  void ensureOpen()
          Guard method that will throw an exception if this sequence is not open, or otherwise return silently.
protected  void finalize()
          Simply invokes close().
protected  int index()
          Returns the index of the current sequence value in this sequence.
 boolean isClosed()
          Returns true if this sequence has been closed, false if not.
 E next()
          Returns the next element from this sequence.
protected abstract  E nextValue(K key, E current)
          This abstract operation creates the next sequence value to be delivered.
protected  void nextValueClose(K key, E value)
          Ensures that this sequence finalises the sequence value just created, if required.
protected abstract  K nextValueOpen(E current)
          Prepares this sequence for the next sequence value to be delivered based on the current value supplied as current.
 void reset()
          Resets this sequence to start over if it is consistent.
protected  void sequenceClose()
          Performs sub-class specific procedures for closing this sequence.
protected abstract  boolean sequenceOpen(Object... arguments)
          Performs sub-class specific initialisation of this sequence before sequence values will be delivered, and returns true upon success.
protected  void sequenceReset()
          Performs sub-class specific reset of this sequence before sequence values will be delivered.
 int size()
          Returns the number of sequence elements in this sequence.
 boolean unique()
          Returns true if this sequence deliver a given sequence value at most one time until reset or restarted.
 
Methods inherited from class dk.rode.thesis.meta.model.AbstractSequence
getStringablePolicy, state, toString, toString
 
Methods inherited from class java.lang.Object
clone, equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface dk.rode.thesis.meta.model.Sequence
copy
 

Field Detail

closed

private boolean closed
True if this sequence has been closed. If so, no more values can be delivered by this sequence.


current

private E current
The current sequence value.

Never null.


index

private int index
The current index into this sequence, used to calculate the size of this sequence.

Interval: 0 <= index <= size (once size has been calculated).


POLICY

protected static final SequencePolicy POLICY
Policy use for logging of this sequence.

Change at compile time for more verbose output.


size

private int size
The size of this sequence, i.e. the number of values delivered.

Calculated once this sequence has restarted.

Initialised to Const.INFINITE.

Constructor Detail

SequenceTemplate

protected SequenceTemplate(Object... arguments)
                    throws SequenceValueException
Constructor, which creates this sequence template.

The initialisation of this sequence is performed with arguments as arguments.

Parameters:
arguments - The arguments, if any, to use in the initialisation of this sequence; can be null.
Throws:
SequenceValueException - If the initialisation fails, or if the initial current value of this sequence cannot be fetched.

SequenceTemplate

protected SequenceTemplate(SequenceTemplate<K,E> sequence,
                           Object... arguments)
                    throws SequenceValueException
Copy constructor, which creates this sequence template based on sequence, i.e. to have the same size, use the same current index, etc.

Initialisation of this sequence template is still performed unless sequence is closed. The initialisation is thus performed with arguments as arguments. Alternatively, if sequence is closed, this sequence will be closed as well.

Parameters:
sequence - The sequence to copy; cannot be null.
arguments - The arguments, if any, to use in the initialisation of this sequence; can be null.
Throws:
NullPointerException - If sequence is null.
SequenceValueException - If the initialisation fails.
See Also:
SequenceTemplate(Object...)
Method Detail

bounded

public boolean bounded()
Description copied from interface: Sequence
Returns true if this sequence is bounded, i.e. deliver values between the initial sequence value and some upper bound.

The same type of sequence may represent both bounded and unbounded sequences and the behaviour is determined and fixed at construction time. Bounded sequences will restart if they deliver consistent values.

Specified by:
bounded in interface Sequence<E>
Returns:
Default implementation returns true.
See Also:
Sequence.unique()

close

public final void close()
Closes this sequence.

Once this sequence has been closed, sequence values can no longer be delivered.

The context should always remember to close a sequence template to ensure that it proper finalisation is made.

Closing this sequence twice has no effect.

Specified by:
close in interface Closeable
See Also:
sequenceClose()

consistent

public boolean consistent()
Description copied from interface: Sequence
Returns true if this sequence is consistent, i.e. deliver the same values, in order, after restart or reset.

Only bounded consistent sequences will restart. Consistent sequences need not deliver unique sequence values.

Instances of the same type of sequences are always consistent or inconsistent; it is determined at design time, not construction time.

Specified by:
consistent in interface Sequence<E>
Returns:
Default implementation returns true.

current

public final E current()
Description copied from interface: Sequence
Returns the current element from this sequence.

This method can be invoked even if Sequence.next() has not been invoked yet, thus delivering the initial value of this sequence.

Specified by:
current in interface Sequence<E>
Returns:
The current element; never null.
Throws:
SequenceValueException - If this sequence has been closed.

ensureOpen

protected final void ensureOpen()
Guard method that will throw an exception if this sequence is not open, or otherwise return silently.


finalize

protected final void finalize()
                       throws Throwable
Simply invokes close().

Overrides:
finalize in class Object
Throws:
Throwable - If the finalising fails.

index

protected final int index()
Returns the index of the current sequence value in this sequence.

Returns:
The index.

isClosed

public final boolean isClosed()
Returns true if this sequence has been closed, false if not.

A closed sequence cannot deliver sequence values, and trying to do so will cause a exception to be thrown.

Returns:
True if this sequence is closed, false if not.
See Also:
ensureOpen()

next

public final E next()
Description copied from interface: Sequence
Returns the next element from this sequence.

Specified by:
next in interface Sequence<E>
Returns:
The next element; never null.
Throws:
SequenceValueException - If this sequence has been closed, or if the next value cannot be fetched.
See Also:
nextValueOpen(E), nextValue(K, E), nextValueClose(K, E)

nextValue

protected abstract E nextValue(K key,
                               E current)
                        throws Exception
This abstract operation creates the next sequence value to be delivered. This is step 2/3 in value creation, where the previous step was nextValueOpen(E) and the last is nextValueClose(K, E).

Parameters:
key - The correlation key just created by nextValueOpen(E); can be null.
current - The current (soon to be previous) sequence value; never null unless initialising this sequence (once).
Returns:
The next sequence value, which will be set as the new current value once next() returns; null means sequence restart, which is only allowed if this sequence is bounded.
Throws:
Exception - In case value construction fails.

nextValueClose

protected void nextValueClose(K key,
                              E value)
                       throws Exception
Ensures that this sequence finalises the sequence value just created, if required. This is step 3/3 in value creation, where the previous steps were nextValueOpen(E) and nextValue(K, E).

Default implementation does nothing.

Parameters:
key - The correlation key just created by nextValueOpen(E); can be null.
value - The sequence value just created by nextValue(K, E); never null.
Throws:
Exception - In case the closing fails; not thrown by the default implementation

nextValueOpen

protected abstract K nextValueOpen(E current)
                            throws Exception
Prepares this sequence for the next sequence value to be delivered based on the current value supplied as current. This is step 1/3 in value creation, where the next steps are nextValue(K, E) and nextValueClose(K, E).

The returned correlation key will be used to identify the same creation process in subsequent calls to nextValue and nextValueClose.

Parameters:
current - The current (soon to be previous) sequence value; never null unless initialising this sequence (once).
Returns:
The correlation key to identify the next sequence value; can be null if not used.
Throws:
Exception - In case the opening fails.

reset

public final void reset()
Description copied from interface: Sequence
Resets this sequence to start over if it is consistent.

If this sequence is consistent, the sequence will restart.

Specified by:
reset in interface Sequence<E>
Overrides:
reset in class AbstractSequence<E>
Throws:
SequenceValueException - If this sequence has been closed, or if the reset fails otherwise.
See Also:
sequenceReset()

sequenceClose

protected void sequenceClose()
                      throws Exception
Performs sub-class specific procedures for closing this sequence. Once this sequence is closed, sequence values can no longer be delivered.

Default implementation does nothing.

Throws:
Exception - Not thrown by the default implementation.
See Also:
sequenceReset(), sequenceOpen(Object...)

sequenceOpen

protected abstract boolean sequenceOpen(Object... arguments)
                                 throws Exception
Performs sub-class specific initialisation of this sequence before sequence values will be delivered, and returns true upon success. In case the initialisation could not be performed, this method returns false, or alternatively throws an exception. If the initialisation fails, this sequences is considered closed.

Initialisation is performed upon construction of new sequences and when copying existing sequences, if needed. The arguments supplied to this (abstract) operation is the varargs arguments supplied at construction time (e.g. via sub-class implementations).

Parameters:
arguments - Arguments required by the initialisation, if any; never null, but can be empty.
Returns:
True if the initialisation succeeded, false if it failed.
Throws:
Exception - If the initialisation fails.
See Also:
sequenceReset(), sequenceClose()

sequenceReset

protected void sequenceReset()
                      throws Exception
Performs sub-class specific reset of this sequence before sequence values will be delivered.

Default implementation does nothing.

Throws:
Exception - Not thrown by the default implementation.
See Also:
sequenceOpen(Object...), sequenceClose()

size

public final int size()
Returns the number of sequence elements in this sequence.

The size is not calculated until this sequence has restarted. Until then, a value of Const.INFINITE is returned.

Returns:
The size, or INFINITE if not calculated yet.

unique

public boolean unique()
Description copied from interface: Sequence
Returns true if this sequence deliver a given sequence value at most one time until reset or restarted.

Unbounded sequences that are unique will never deliver the same sequence value more than once.

The same type of sequence may represent both unique and not unique sequences and the behaviour is determined and fixed at construction time.

Specified by:
unique in interface Sequence<E>
Returns:
Default implementation returns true.
See Also:
Sequence.consistent()

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.