uk.org.blankaspect.nlf
Class Document

java.lang.Object
  extended by uk.org.blankaspect.nlf.Document

public class Document
extends java.lang.Object

This class implements a Nested List File document. A document is a representation of an entire Nested List File. The structure of the document is a rooted tree whose nodes are chunks. Leaf nodes are simple chunks, branch nodes are lists, and the root node is the document's root list.

This class provides methods for reading from and writing to a Nested List File, which, because of the need to seek backwards and forwards in the file, is opened as a random access file, java.io.RandomAccessFile, rather than as an input or output stream. The methods of this class supervise the reading and writing of a document, but the content of simple chunks is read and written by the reader and writer that are set on each chunk.

Reading a document is done in two passes: on the first pass, the file is read and parsed to determine the document's structure (ie, to generate its tree); on the second pass, the content of the simple chunks is read. The first pass is performed by the read(java.io.File) method of this class, which sets the identifier and size of each chunk, and sets a default ChunkReader object on each chunk to allow its data to be read from the file. The second pass is performed by the code that wants to access the chunk data, by calling the methods that are provided by the chunk's reader. Because the document's tree and the location of each chunk are known after the first pass, the chunks can be processed in any order during the second pass, and the chunk data can be read multiple times.

Writing a document is not as straightforward as reading it because the end of a chunk is not marked by a delimiter but is specified implicitly by the size field in the chunk header. If the size of a chunk is not known when its chunk header is written, the header must be written with a dummy size, then rewritten after the chunk data have been written and their size determined. The mechanism used by this class's write(java.io.File) method is for a chunk to indicate, by returning a negative value from its getSize() method, that its size is unknown when its header is written. In this case, the size field in the header is fixed up after the chunk data are written.

To facilitate the writing of chunks whose content is not fully known when it is written (eg, because it depends on subsequent chunks), the write(java.io.File) method writes chunk data in two passes. On the first pass, a chunk can signal, through the value returned by the reset(int) method of its writer, that it should be written again on the second pass. The size of the chunk must not change between the first pass and the second pass. An attributes chunk uses its setRewrite(boolean) method to set the flag that is used by its default writer.

A random access file that is opened on a document is closed by the document's finalize() method when there are no more references to the Document object, but is recommended that the file be closed explicitly with the document's close() or closeIgnoreException() method. The latter, as its name suggests, ignores any exception that is thrown when the file is closed.

Since:
1.0
See Also:
Chunk, ChunkList

Field Summary
static byte[] FILE_ID
           
 
Constructor Summary
Document(boolean littleEndian)
          Constructs a document with the specified byte order.
 
Method Summary
 void close()
          Closes a random access file that is open on this document.
 void closeIgnoreException()
          Closes a random access file that is open on this document, ignoring any exception that occurs when the file is closed.
 Chunk createChunk(Id id)
          Creates a general chunk with the specified identifier.
 ChunkList createList(Id instanceId)
          Creates a chunk list with the specified list-instance identifier.
 ChunkList createRootList(Id instanceId)
          Creates a root list for this document with the specified list-instance identifier.
protected  void finalize()
          Ensures that a random access file that was opened on this document is closed when there are no more references to the document.
 ChunkList getRootList()
          Returns the root list of the document.
 boolean isLittleEndian()
          Returns a flag to indicate the byte order of size fields in the document.
 void processChunks(NlfConstants.TraversalOrder traversalOrder, Chunk.Processor processor)
          Traverses the document tree in the specified order, calling the specified processor on each chunk that is visited.
 void read(java.io.File file)
          Reads the specified file and parses it to create a list tree for this document.
 org.w3c.dom.Document toXml()
          Returns this document as an XML document.
 void write(java.io.File file)
          Writes this document to the specified file.
 
Methods inherited from class java.lang.Object
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

FILE_ID

public static final byte[] FILE_ID
Constructor Detail

Document

public Document(boolean littleEndian)
Constructs a document with the specified byte order.

Parameters:
littleEndian - true if the byte order of size fields in the document is little-endian; false if the byte order is big-endian.
Since:
1.0
Method Detail

finalize

protected void finalize()
                 throws java.io.IOException
Ensures that a random access file that was opened on this document is closed when there are no more references to the document.

Overrides:
finalize in class java.lang.Object
Throws:
java.io.IOException - if an I/O error occurs.
Since:
1.0
See Also:
close()

getRootList

public ChunkList getRootList()
Returns the root list of the document.

Returns:
the root list of the document.
Since:
1.0

isLittleEndian

public boolean isLittleEndian()
Returns a flag to indicate the byte order of size fields in the document.

Returns:
true if the byte order of size fields in the document is little-endian; false if the byte order is big-endian.
Since:
1.0

createChunk

public Chunk createChunk(Id id)
                  throws NlfUncheckedException
Creates a general chunk with the specified identifier. The chunk will belong to this document and can be added only to a list that belongs to this document.

Parameters:
id - the identifier of the chunk.
Returns:
a general chunk with identifier id that belongs to this document.
Throws:
NlfUncheckedException - RESERVED_IDENTIFIER: if id is a reserved identifier.
Since:
1.0

createList

public ChunkList createList(Id instanceId)
                     throws NlfUncheckedException
Creates a chunk list with the specified list-instance identifier. The list will belong to this document: it can contain only chunks and lists that belong to this document, and it can be added only to another list that belongs to this document.

Parameters:
instanceId - the list-instance identifier of the list.
Returns:
a list with list-instance identifier instanceId that belongs to this document.
Throws:
NlfUncheckedException - RESERVED_IDENTIFIER: if instanceId is a reserved identifier.
Since:
1.0

createRootList

public ChunkList createRootList(Id instanceId)
                         throws NlfUncheckedException
Creates a root list for this document with the specified list-instance identifier. The root list of this document will be set to the list that is created by this method. The list will be belong to this document and can contain only chunks and lists that belong to this document.

Parameters:
instanceId - the list-instance identifier of the root list.
Returns:
a list with list-instance identifier instanceId that belongs to this document and that has been set as the root list of this document.
Throws:
NlfUncheckedException - RESERVED_IDENTIFIER: if instanceId is a reserved identifier.
Since:
1.0

read

public void read(java.io.File file)
          throws NlfException,
                 NlfUncheckedException
Reads the specified file and parses it to create a list tree for this document. The file is opened as a java.io.RandomAccessFile for reading only, and the file remains open with a shared lock when this method returns normally. (The file is closed if the method terminates with an exception.) The random access file should be closed with close() when the chunk data have been read and no further file access is required.

This method sets the identifier and size of each chunk, and sets a default chunk reader object on each chunk to allow its data to be read from the file.

Parameters:
file - the file that is to be read.
Throws:
NlfException - if
  • the specified file cannot be opened, accessed or locked, or
  • an error occurs when reading the file, or
  • the file is malformed or otherwise invalid.
NlfUncheckedException - FILE_IS_OPEN_ON_DOCUMENT: if a random access file is already open on this document.
Since:
1.0

write

public void write(java.io.File file)
           throws NlfException,
                  NlfUncheckedException
Writes this document to the specified file. This method calls the writer object of each chunk to write the chunk's data.

If the size of a chunk is not known when its chunk header is written, the header will be written with a dummy size, then rewritten after the chunk data have been written and their size determined. A chunk can indicate, by returning a negative value from its getSize() method, that its size is unknown when its header is written. In this case, the size field in the header is fixed up after the chunk data are written.

To facilitate the writing of chunks whose content depends on subsequent chunks, this method writes chunk data in two passes. On the first pass, a chunk can signal, through the value returned by the reset(int) method of its writer, that it should be written again on the second pass. The size of the chunk must not change between the first pass and the second pass.

The document is written to a temporary file, which is renamed to the specified file when the document has been successfully written. Until the temporary file has been written, an exception that is thrown by this method will refer to the temporary file, not to the specified file. The temporary file will be deleted if a handled exception is thrown, unless an existing file with the same pathname as the the specified file has been deleted prior to renaming the temporary file.

Parameters:
file - the file that is to be written.
Throws:
NlfException - if
  • a temporary file cannot be opened, accessed, locked or closed, or
  • an error occurs when writing the file, or
  • an existing file with the same pathname as the specified file cannot be deleted, or
  • the temporary file cannot be renamed to the specified file after it is written.
NlfUncheckedException - FILE_IS_OPEN_ON_DOCUMENT: if a random access file is already open on this document.
Since:
1.0

close

public void close()
           throws java.io.IOException
Closes a random access file that is open on this document.

Throws:
java.io.IOException - if an I/O error occurs.
Since:
1.0
See Also:
closeIgnoreException()

closeIgnoreException

public void closeIgnoreException()
Closes a random access file that is open on this document, ignoring any exception that occurs when the file is closed. This method is intended to be used by an exception handler.

Since:
1.0
See Also:
close()

toXml

public org.w3c.dom.Document toXml()
                           throws NlfException
Returns this document as an XML document.

Returns:
the XML document that is generated from this document.
Throws:
NlfException -
  • FAILED_TO_CREATE_XML_DOCUMENT: if an exception occurs in creating the XML document;
  • ERROR_GENERATING_XML_DOCUMENT: if an exception occurs in generating one of the elements of the XML document.
Since:
1.0

processChunks

public void processChunks(NlfConstants.TraversalOrder traversalOrder,
                          Chunk.Processor processor)
                   throws java.lang.IllegalArgumentException,
                          TerminatedException
Traverses the document tree in the specified order, calling the specified processor on each chunk that is visited.

Parameters:
traversalOrder - the order, breadth-first or depth-first, in which the tree is to be traversed.
processor - the processor that is to be called on each chunk that is visited.
Throws:
java.lang.IllegalArgumentException - if traversalOrder is null or processor is null.
TerminatedException - if the traversal of the tree is terminated.
Since:
1.0