org.crosswire.jsword.passage
Class AbstractPassage

java.lang.Object
  extended by org.crosswire.jsword.passage.AbstractPassage
All Implemented Interfaces:
Serializable, Cloneable, Comparable, Iterable, Key, Passage
Direct Known Subclasses:
BitwisePassage, DistinctPassage, PassageTally, RangedPassage

public abstract class AbstractPassage
extends Object
implements Passage

This is a base class to help with some of the common implementation details of being a Passage.

Importantly, this class takes care of Serialization in a general yet optimized way. I think I am going to have a look at replacement here.

Author:
Joe Walker [joe at eireneh dot com]
See Also:
for license details. The copyright to this program is held by it's authors., Serialized Form

Nested Class Summary
protected static class AbstractPassage.VerseRangeIterator
          Skip over verses that are part of a range
 
Field Summary
protected static int BITWISE
          Serialization type constant for a BitWise layout
protected static int DISTINCT
          Serialization type constant for a Distinct layout
protected  List listeners
          Support for change notification
private static Logger log
          The log stream
protected static int METHOD_COUNT
          Count of serializations methods
protected  String originalName
          The original string for picky users
private  Key parent
          The parent key.
protected static int RANGED
          Serialization type constant for a Ranged layout
static String REF_ALLOWED_DELIMS
          What characters can we use to separate VerseRanges in a Passage
static String REF_OSIS_DELIM
          What characters should we use to separate VerseRanges in a Passage
static String REF_PREF_DELIM
          What characters should we use to separate VerseRanges in a Passage
protected  int skipNormalization
          Do we skip normalization for now - if we want to skip then we increment this, and the decrement it when done.
protected  int suppressEvents
          If we have several changes to make then we increment this and then decrement it when done (and fire an event off).
 
Constructor Summary
protected AbstractPassage()
          Setup that leaves original name being null
protected AbstractPassage(String passageName)
          Setup the original name of this reference
 
Method Summary
 void addAll(Key key)
          Adds the specified element to this set if it is not already present.
 void addPassageListener(PassageListener li)
          Event Listeners - Add Listener
protected  void addVerses(String refs)
          Create a Passage from a human readable string.
 void blur(int verses, RestrictionType restrict)
          Widen the range of the verses/keys in this list.
 int booksInPassage()
          How many books are there in this Passage
 boolean canHaveChildren()
          Returns true if the receiver is a leaf node and can not have children.
 int chaptersInPassage(int book)
          How many chapters are there in a particular book in this Passage
 void clear()
          Removes all of the elements from this set (optional operation).
 Object clone()
          This needs to be declared here so that it is visible as a method on a derived Key.
 int compareTo(Object obj)
           
 boolean contains(Key key)
          Returns true if this set contains the specified element.
 boolean containsAll(Passage that)
          Returns true if this Passage contains all of the verses in that Passage
 int countRanges(RestrictionType restrict)
          Like countVerses() that counts VerseRanges instead of Verses Returns the number of fragments in this collection.
 int countVerses()
          Returns the number of verses in this collection.
 boolean equals(Object obj)
           
protected  void fireContentsChanged(Object source, Verse start, Verse end)
          AbstractPassage subclasses must call this method before one or more elements of the list are added.
protected  void fireIntervalAdded(Object source, Verse start, Verse end)
          AbstractPassage subclasses must call this method after one or more elements of the list are added.
protected  void fireIntervalRemoved(Object source, Verse start, Verse end)
          AbstractPassage subclasses must call this method before one or more elements of the list are added.
 Key get(int index)
          Gets a key from a specific point in this list.
 int getChildCount()
          Returns the number of elements in this set (its cardinality).
 String getName()
          A Human readable version of the Key.
 String getName(Key base)
          Translate the Key into a human readable string, with the assumption that the specified Key has just been output, so if we are in the same region, we do not need to display the region name, and so on.
 String getOsisID()
          The OSIS defined id specification for this Key.
 String getOsisRef()
          The OSIS defined reference specification for this Key.
 String getOverview()
          A summary of the verses in this Passage For example "10 verses in 4 books"
 Key getParent()
          All keys have parents unless they are the root of a Key.
 VerseRange getRangeAt(int offset, RestrictionType restrict)
          Get a specific VerseRange from this collection
 Verse getVerseAt(int offset)
          Get a specific Verse from this collection
 int hashCode()
           
 int indexOf(Key that)
          Reverse a Key into the position the key holds in the list
 boolean isEmpty()
          Does this Passage have 0 members
 boolean lowerEventSuppresionAndTest()
          If things want to prevent event firing because they are doing a set of changes that should be notified in one go, they should call raiseEventSuppression() and when done call this.
 void lowerNormalizeProtection()
          If things want to prevent normalization because they are doing a set of changes that should be normalized in one go, they should call raiseNormalizeProtection() and when done call this.
(package private)  void normalize()
          We sometimes need to sort ourselves out ...
 void optimizeReads()
          For preformance reasons we may well want to hint to the Passage that we have done editing it for now and that it is safe to cache certain values to speed up future reads.
protected  void optimizeWrites()
          Simple method to instruct children to stop caching results
 void raiseEventSuppresion()
          If things want to prevent event firing because they are doing a set of changes that should be notified in one go, this is what to call.
 void raiseNormalizeProtection()
          If things want to prevent normalization because they are doing a set of changes that should be normalized in one go, this is what to call.
 Iterator rangeIterator(RestrictionType restrict)
          Like verseElements() that iterates over VerseRanges instead of Verses.
 void readDescription(Reader in)
          To be compatible with humans we read/write ourselves to a file that a human can read and even edit.
private  void readObject(ObjectInputStream is)
          Serialization support.
protected  void readObjectSupport(ObjectInputStream is)
          Write out the object to the given ObjectOutputStream
 void removeAll(Key key)
          Removes the specified elements from this set if it is present.
 void removePassageListener(PassageListener li)
          Event Listeners - Remove Listener
 void retainAll(Key key)
          Removes all but the specified element from this set.
 void setParent(Key parent)
          Set a parent Key.
 String toString()
           
protected static VerseRange toVerseRange(Object base)
          Convert the Object to a VerseRange.
 Passage trimRanges(int count, RestrictionType restrict)
          Ensures that there are a maximum of count VerseRanges in this Passage.
 Passage trimVerses(int count)
          Ensures that there are a maximum of count Verses in this Passage.
 int versesInPassage(int book, int chapter)
          How many chapters are there in a particular book in this Passage Note that versesInPassage(ref, 0, 0) == ref.countVerses()
 void writeDescription(Writer out)
          To be compatible with humans we read/write ourselves to a file that a human can read and even edit.
protected  void writeObjectSupport(ObjectOutputStream out)
          Write out the object to the given ObjectOutputStream.
 
Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface org.crosswire.jsword.passage.Passage
add, remove
 
Methods inherited from interface org.crosswire.common.util.Iterable
iterator
 

Field Detail

log

private static final Logger log
The log stream


BITWISE

protected static final int BITWISE
Serialization type constant for a BitWise layout

See Also:
Constant Field Values

DISTINCT

protected static final int DISTINCT
Serialization type constant for a Distinct layout

See Also:
Constant Field Values

RANGED

protected static final int RANGED
Serialization type constant for a Ranged layout

See Also:
Constant Field Values

METHOD_COUNT

protected static final int METHOD_COUNT
Count of serializations methods

See Also:
Constant Field Values

parent

private transient Key parent
The parent key. See the key interface for more information. NOTE(joe): These keys are not serialized, should we?

See Also:
Key

listeners

protected transient List listeners
Support for change notification


originalName

protected transient String originalName
The original string for picky users


suppressEvents

protected transient int suppressEvents
If we have several changes to make then we increment this and then decrement it when done (and fire an event off). If the cost of calculating the parameters to the fire is high then we can check that this is 0 before doing the calculation.


skipNormalization

protected transient int skipNormalization
Do we skip normalization for now - if we want to skip then we increment this, and the decrement it when done.


REF_ALLOWED_DELIMS

public static final String REF_ALLOWED_DELIMS
What characters can we use to separate VerseRanges in a Passage

See Also:
Constant Field Values

REF_PREF_DELIM

public static final String REF_PREF_DELIM
What characters should we use to separate VerseRanges in a Passage

See Also:
Constant Field Values

REF_OSIS_DELIM

public static final String REF_OSIS_DELIM
What characters should we use to separate VerseRanges in a Passage

See Also:
Constant Field Values
Constructor Detail

AbstractPassage

protected AbstractPassage()
Setup that leaves original name being null


AbstractPassage

protected AbstractPassage(String passageName)
Setup the original name of this reference

Parameters:
passageName - The text originally used to create this Passage.
Method Detail

compareTo

public int compareTo(Object obj)
Specified by:
compareTo in interface Comparable

clone

public Object clone()
Description copied from interface: Key
This needs to be declared here so that it is visible as a method on a derived Key.

Specified by:
clone in interface Key
Overrides:
clone in class Object
Returns:
A complete copy of ourselves

equals

public boolean equals(Object obj)
Overrides:
equals in class Object

hashCode

public int hashCode()
Overrides:
hashCode in class Object

getName

public String getName()
Description copied from interface: Key
A Human readable version of the Key. For Biblical passages this uses short books names, and the shortest sensible rendering eg "Mat 3:1-4" and "Mar 1:1, 3, 5" and "3Jo, Jude"

Specified by:
getName in interface Key
Returns:
a String containing a description of the Key

getName

public String getName(Key base)
Description copied from interface: Key
Translate the Key into a human readable string, with the assumption that the specified Key has just been output, so if we are in the same region, we do not need to display the region name, and so on.

Specified by:
getName in interface Key
Parameters:
base - The key to use to cut down unnecessary output.
Returns:
The string representation

getOsisRef

public String getOsisRef()
Description copied from interface: Key
The OSIS defined reference specification for this Key. When the key is a single element, it is an OSIS book name with '.' separating the parts. When the key is multiple elements, it uses a range notation. Note, this will create a comma separated list of ranges, which is improper OSIS.

Specified by:
getOsisRef in interface Key
Returns:
a String containing the OSIS description of the verses

getOsisID

public String getOsisID()
Description copied from interface: Key
The OSIS defined id specification for this Key. When the key is a single element, it is an OSIS book name with '.' separating the parts. When the key is multiple elements, it uses a space to separate each.

Specified by:
getOsisID in interface Key
Returns:
a String containing the OSIS description of the verses

toString

public String toString()
Overrides:
toString in class Object

getOverview

public String getOverview()
Description copied from interface: Passage
A summary of the verses in this Passage For example "10 verses in 4 books"

Specified by:
getOverview in interface Passage
Returns:
a String containing an overview of the verses

isEmpty

public boolean isEmpty()
Description copied from interface: Key
Does this Passage have 0 members

Specified by:
isEmpty in interface Key
Returns:
true if this set contains no elements.

countVerses

public int countVerses()
Description copied from interface: Passage
Returns the number of verses in this collection. Like Collection.size() This does not mean the Passage needs to use Verses, just that it understands the concept.

Specified by:
countVerses in interface Passage
Returns:
the number of Verses in this collection
See Also:
Verse

countRanges

public int countRanges(RestrictionType restrict)
Description copied from interface: Passage
Like countVerses() that counts VerseRanges instead of Verses Returns the number of fragments in this collection. This does not mean the Passage needs to use VerseRanges, just that it understands the concept.

Specified by:
countRanges in interface Passage
Parameters:
restrict - Do we break ranges at chapter/book boundries
Returns:
the number of VerseRanges in this collection
See Also:
VerseRange

booksInPassage

public int booksInPassage()
Description copied from interface: Passage
How many books are there in this Passage

Specified by:
booksInPassage in interface Passage
Returns:
The number of distinct books

chaptersInPassage

public int chaptersInPassage(int book)
                      throws NoSuchVerseException
Description copied from interface: Passage
How many chapters are there in a particular book in this Passage

Specified by:
chaptersInPassage in interface Passage
Parameters:
book - The book to check (0 for distinct chapters in all books)
Returns:
The number of distinct chapters
Throws:
NoSuchVerseException - if the book is invalid

versesInPassage

public int versesInPassage(int book,
                           int chapter)
                    throws NoSuchVerseException
Description copied from interface: Passage
How many chapters are there in a particular book in this Passage Note that versesInPassage(ref, 0, 0) == ref.countVerses()

Specified by:
versesInPassage in interface Passage
Parameters:
book - The book to check (0 for distinct chapters in all books)
chapter - The chapter to check (0 for distinct verses in all chapters)
Returns:
The number of distinct chapters
Throws:
NoSuchVerseException - if the book/chapter is invalid

getVerseAt

public Verse getVerseAt(int offset)
                 throws ArrayIndexOutOfBoundsException
Description copied from interface: Passage
Get a specific Verse from this collection

Specified by:
getVerseAt in interface Passage
Parameters:
offset - The verse offset (legal values are 0 to countVerses()-1)
Returns:
The Verse
Throws:
ArrayIndexOutOfBoundsException - If the offset is out of range

getRangeAt

public VerseRange getRangeAt(int offset,
                             RestrictionType restrict)
                      throws ArrayIndexOutOfBoundsException
Description copied from interface: Passage
Get a specific VerseRange from this collection

Specified by:
getRangeAt in interface Passage
Parameters:
offset - The verse range offset (legal values are 0 to countRanges()-1)
restrict - Do we break ranges at chapter/book boundries
Returns:
The Verse Range
Throws:
ArrayIndexOutOfBoundsException - If the offset is out of range

rangeIterator

public Iterator rangeIterator(RestrictionType restrict)
Description copied from interface: Passage
Like verseElements() that iterates over VerseRanges instead of Verses. Exactly the same data will be traversed, however using rangeIterator() will usually give less iterations (and never more)

Specified by:
rangeIterator in interface Passage
Parameters:
restrict - Do we break ranges over chapters
Returns:
A list enumerator

containsAll

public boolean containsAll(Passage that)
Description copied from interface: Passage
Returns true if this Passage contains all of the verses in that Passage

Specified by:
containsAll in interface Passage
Parameters:
that - Passage to be checked for containment in this collection.
Returns:
true if this reference contains all of the Verses in that Passage

trimVerses

public Passage trimVerses(int count)
Description copied from interface: Passage
Ensures that there are a maximum of count Verses in this Passage. If there were more than count Verses then a new Passage is created containing the Verses from count+1 onwards. If there was not greater than count in the Passage, then the passage remains unchanged, and null is returned.

Specified by:
trimVerses in interface Passage
Parameters:
count - The maximum number of Verses to allow in this collection
Returns:
A new Passage conatining the remaining verses or null
See Also:
Verse

trimRanges

public Passage trimRanges(int count,
                          RestrictionType restrict)
Description copied from interface: Passage
Ensures that there are a maximum of count VerseRanges in this Passage. If there were more than count VerseRanges then a new Passage is created containing the VerseRanges from count+1 onwards. If there was not greater than count in the Passage, then the passage remains unchanged, and null is returned.

Specified by:
trimRanges in interface Passage
Parameters:
count - The maximum number of VerseRanges to allow in this collection
restrict - Do we break ranges at chapter/book boundries
Returns:
A new Passage conatining the remaining verses or null
See Also:
VerseRange

addAll

public void addAll(Key key)
Description copied from interface: Key
Adds the specified element to this set if it is not already present.

Specified by:
addAll in interface Key
Parameters:
key - element to be added to this set.

removeAll

public void removeAll(Key key)
Description copied from interface: Key
Removes the specified elements from this set if it is present.

Specified by:
removeAll in interface Key
Parameters:
key - object to be removed from this set, if present.

retainAll

public void retainAll(Key key)
Description copied from interface: Key
Removes all but the specified element from this set.

Specified by:
retainAll in interface Key
Parameters:
key - object to be left in this set.

clear

public void clear()
Description copied from interface: Key
Removes all of the elements from this set (optional operation). This set will be empty after this call returns (unless it throws an exception).

Specified by:
clear in interface Key

blur

public void blur(int verses,
                 RestrictionType restrict)
Description copied from interface: Key
Widen the range of the verses/keys in this list. This is primarily for "find x within n verses of y" type applications.

Specified by:
blur in interface Key
Parameters:
verses - The number of verses/keys to widen by
restrict - How should we restrict the blurring?
See Also:
Passage

writeDescription

public void writeDescription(Writer out)
                      throws IOException
Description copied from interface: Passage
To be compatible with humans we read/write ourselves to a file that a human can read and even edit. OLB verse.lst integration is a good goal here.

Specified by:
writeDescription in interface Passage
Parameters:
out - The stream to write to
Throws:
IOException - If the file/network etc breaks

readDescription

public void readDescription(Reader in)
                     throws IOException,
                            NoSuchVerseException
Description copied from interface: Passage
To be compatible with humans we read/write ourselves to a file that a human can read and even edit. OLB verse.lst integration is a good goal here.

Specified by:
readDescription in interface Passage
Parameters:
in - The stream to read from
Throws:
IOException - If the file/network etc breaks
NoSuchVerseException - If the file was invalid

optimizeReads

public void optimizeReads()
Description copied from interface: Passage
For preformance reasons we may well want to hint to the Passage that we have done editing it for now and that it is safe to cache certain values to speed up future reads. Any action taken by this method will be undone simply by making a future edit, and the only loss in calling optimizeReads() is a loss of time if you then persist in writing to the Passage.

Specified by:
optimizeReads in interface Passage

optimizeWrites

protected void optimizeWrites()
Simple method to instruct children to stop caching results


addPassageListener

public void addPassageListener(PassageListener li)
Description copied from interface: Passage
Event Listeners - Add Listener

Specified by:
addPassageListener in interface Passage
Parameters:
li - The listener to add

removePassageListener

public void removePassageListener(PassageListener li)
Description copied from interface: Passage
Event Listeners - Remove Listener

Specified by:
removePassageListener in interface Passage
Parameters:
li - The listener to remove

contains

public boolean contains(Key key)
Description copied from interface: Key
Returns true if this set contains the specified element.

Specified by:
contains in interface Key
Specified by:
contains in interface Passage
Parameters:
key - element whose presence in this set is to be tested.
Returns:
true if this set contains the specified element.

getChildCount

public int getChildCount()
Description copied from interface: Key
Returns the number of elements in this set (its cardinality). If this set contains more than Integer.MAX_VALUE elements, returns Integer.MAX_VALUE.

Specified by:
getChildCount in interface Key
Returns:
the number of elements in this set (its cardinality).

indexOf

public int indexOf(Key that)
Description copied from interface: Key
Reverse a Key into the position the key holds in the list

Specified by:
indexOf in interface Key
Parameters:
that - The Key to find
Returns:
The index of the key or -1 if the key is not in the list

canHaveChildren

public boolean canHaveChildren()
Description copied from interface: Key
Returns true if the receiver is a leaf node and can not have children. Any attempt to add()/remove() wlll throw

Specified by:
canHaveChildren in interface Key

get

public Key get(int index)
Description copied from interface: Key
Gets a key from a specific point in this list.

Specified by:
get in interface Key
Parameters:
index - The index of the Key to retrieve
Returns:
The specified key

getParent

public Key getParent()
Description copied from interface: Key
All keys have parents unless they are the root of a Key.

Specified by:
getParent in interface Key
Returns:
The parent of this tree, or null if this Key is the root.

setParent

public void setParent(Key parent)
Set a parent Key. This allows us to follow the Key interface more closely, although the concept of a parent for a verse is fairly alien.

Parameters:
parent - The parent Key for this verse

fireIntervalAdded

protected void fireIntervalAdded(Object source,
                                 Verse start,
                                 Verse end)
AbstractPassage subclasses must call this method after one or more elements of the list are added. The changed elements are specified by a closed interval from start to end.

Parameters:
source - The thing that changed, typically "this".
start - One end of the new interval.
end - The other end of the new interval.
See Also:
PassageListener

fireIntervalRemoved

protected void fireIntervalRemoved(Object source,
                                   Verse start,
                                   Verse end)
AbstractPassage subclasses must call this method before one or more elements of the list are added. The changed elements are specified by a closed interval from start to end.

Parameters:
source - The thing that changed, typically "this".
start - One end of the new interval.
end - The other end of the new interval.
See Also:
PassageListener

fireContentsChanged

protected void fireContentsChanged(Object source,
                                   Verse start,
                                   Verse end)
AbstractPassage subclasses must call this method before one or more elements of the list are added. The changed elements are specified by a closed interval from start to end.

Parameters:
source - The thing that changed, typically "this".
start - One end of the new interval.
end - The other end of the new interval.
See Also:
PassageListener

addVerses

protected void addVerses(String refs)
                  throws NoSuchVerseException
Create a Passage from a human readable string. The opposite of toString(). Since this method is not public it leaves control of suppress_events up to the people that call it.

Parameters:
refs - A String containing the text of the RangedPassage
Throws:
NoSuchVerseException - if the string is invalid

normalize

void normalize()
We sometimes need to sort ourselves out ... I don't think we need to be synchronised since we are private and we could check that all public calling of normalize() are synchronised, however this is safe, and I don't think there is a cost associated with a double synchronize. (?)


raiseNormalizeProtection

public void raiseNormalizeProtection()
If things want to prevent normalization because they are doing a set of changes that should be normalized in one go, this is what to call. Be sure to call lowerNormalizeProtection() when you are done.


lowerNormalizeProtection

public void lowerNormalizeProtection()
If things want to prevent normalization because they are doing a set of changes that should be normalized in one go, they should call raiseNormalizeProtection() and when done call this. This also calls normalize() if the count reaches zero.


raiseEventSuppresion

public void raiseEventSuppresion()
If things want to prevent event firing because they are doing a set of changes that should be notified in one go, this is what to call. Be sure to call lowerEventSuppression() when you are done.


lowerEventSuppresionAndTest

public boolean lowerEventSuppresionAndTest()
If things want to prevent event firing because they are doing a set of changes that should be notified in one go, they should call raiseEventSuppression() and when done call this.

Returns:
true if it is then safe to fire an event.

toVerseRange

protected static VerseRange toVerseRange(Object base)
                                  throws ClassCastException
Convert the Object to a VerseRange. If base is a Verse then return a VerseRange of zero length.

Parameters:
base - The object to be cast
Returns:
The VerseRange
Throws:
ClassCastException - If this is not a Verse or a VerseRange

writeObjectSupport

protected void writeObjectSupport(ObjectOutputStream out)
                           throws IOException
Write out the object to the given ObjectOutputStream. There are 3 ways of doing this - according to the 3 implementations of Passage.
  • Distinct: If we write out a list if verse ordinals then the space used is 4 bytes per verse.
  • Bitwise: If we write out a bitmap then the space used is something like 31104/8 = 4k bytes.
  • Ranged: The we write a list of start/end pairs then the space used is 8 bytes per range.
Since we can take our time about this section, we calculate the optimal storage method before we do the saving. If some methods come out equal first then bitwise is preferred, then distinct, then ranged, because I imagine that for speed of de-serialization this is the sensible order. I've not tested it though.

Parameters:
out - The stream to write our state to
Throws:
IOException - if the read fails

readObject

private void readObject(ObjectInputStream is)
                 throws IOException,
                        ClassNotFoundException
Serialization support.

Parameters:
is -
Throws:
IOException
ClassNotFoundException

readObjectSupport

protected void readObjectSupport(ObjectInputStream is)
                          throws IOException,
                                 ClassNotFoundException
Write out the object to the given ObjectOutputStream

Parameters:
is - The stream to read our state from
Throws:
IOException - if the read fails
ClassNotFoundException - If the read data is incorrect

Copyright ยจ 2003-2006