Class Layout
The syntax of a layout in EBNF (Extended Backus–Naur Form) is recursively defined as follows:
layout = [ entryList, [EOL] ] entryList = indEntry, { EOL, indEntry } indEntry = [ comment ], indent, entry indent = level * INDENT entry = KEY, WS, "=", WS, VALUE | KEY, "[]", seqVal | KEY, layoutVal layoutVal = [ EOL, entryList ] seqVal = { EOL, [ comment ], indent, element } element = TEXT | "[]", seqVal | ".", EOL, layoutVal comment = cLine, { cLine } cLine = indent, "#", CTEXT, EOL EOL = ? any predefined non-empty sequence of characters identifying the end of a line. ? INDENT = ? any predefined non-empty sequence of characters with codes less than or equal to SPACE U+0020 and not containing EOL. ? WS = ? any empty or non-empty sequence of characters with codes less than or equal to SPACE U+0020 and not containing EOL. ? KEY = ? any non-empty sequence of characters that starts and ends with a character having a code greater than SPACE U+0020 and that starts with a character different from the NUMBER SIGN ('The terminal symbol#
') U+0023 and that neither contains the EQUALS SIGN ('=
') U+003D nor EOL. ? VALUE = ? any empty or non-empty sequence of characters that starts and ends with a character having a code greater than SPACE U+0020 and that does not contain EOL. ? TEXT = ? any non-empty sequence of characters that starts and ends with a character having a code greater than SPACE U+0020 and that starts with a character different from the NUMBER SIGN ('#
') U+0023 and that does not contain EOL. ? CTEXT = ? any empty or non-empty sequence of characters that does not contain EOL. ?
EOL
denotes a line terminator and the symbol level
denotes an integer
variable called the level of indentation.
Initially this variable is set to 0 and it is incremented by one each time a
layoutVal
or seqVal
non-terminal symbol is started to be
applied and it is decremented by one each time that layoutVal
or that
seqVal
non-terminal symbol is finished to be applied.
Thus, a layout can roughly be seen as a collection of key-value pairs where
the key is some text and the value is either a string, a sequence or again a
layout.
A key-value pair with a value being a string is also known as a
property, e.g., "age = 38
".
An element of a sequence can be a string, again a sequence or a layout.
Applying three space characters for indentation, a database with a name equal to "TriasDB" containing a single table "Configuration" may be laid out like this:
name = TriasDB version = 1.5 consistencyNumber = 0 # cipherFactoryClassName = com.example.CipherFactory # cipherChallenge = 29jxv5pqc56i69ys forceWriteCommit = off recFile = rec tables Configuration columns[] . name = ID typeDesc = s!i58v . name = Locales typeDesc = s!i40v . name = Timestamp typeDesc = l!i8 store nobsRowRef = 1 flDataFile = Configuration_fldDue to its recursive definition the entries under
tables
,
Configuration
, store
, and the dots (.
) are themselves
layouts.
Note that empty layouts, empty sequences and even empty string property
values are allowed.
Indentation is the only way to give a layout a more complex structure than just a flat set of key-value pairs. Changing the indentations manually within a file containing a layout must be done with care. It is an error if a line of text starts with a sequence of white spaces that can't be matched to an indentation. (A white space is a character with a code less than or equal to SPACE U+0020.) It is also an error if any line of text forming an entry in a layout or forming an element in a sequence has an indentation level that is too large, like the last line of text in the following example:
store nobsRowRef = 1 flDataFile = Configuration_fld
Note, however, that
store nobsRowRef = 1 flDataFile = Configuration_fldis perfectly correct, though, this might not be what the user wanted because the last entry is an entry of the "root" layout and not an entry of the nested
store
layout.
Note that comments must be properly indented. Therefore
# # This is a store # store nobsRowRef = 1 # The backing file of the store flDataFile = Configuration_fld
is perfectly correct, whereas
store nobsRowRef = 1 # The backing file of the store flDataFile = Configuration_fld
and
store nobsRowRef = 1 # Now comes the table class name flDataFile = Configuration_fldraise an exception because the comment is not properly indented.
This class provides the following operations:
- Two factory methods for creating a layout by reading it from a UTF-8 encoded text file and input stream, respectively.
- A constructor for creating an empty layout.
- A copy constructor for creating a memory independent copy of an already existing layout.
- Methods for creating, returning and manipulating the entries of a layout.
- A method for saving the changes made to a layout.
- Two methods for writing a layout to a UTF-8 encoded text file and output stream, respectively.
- Author:
- Beat Hörmann
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final class
A layout entry.static final class
Defines the sequence value type of a layout. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionfinal Layout
Adds the specified layout with the specified key.final Layout
add
(String key, Layout.Seq seq) Adds the specified sequence with the specified key.final Layout
Adds the specified string value with the specified key.final Layout
Creates a new layout, adds it to this layout with the specified key and returns the new layout.final Layout.Seq
Creates a new sequence, adds it to this layout with the specified key and returns the new sequence.final boolean
Returnstrue
if this layout contains an entry with the specified key.final Layout.LtEntry[]
entries()
Returns the entries of this layout.static final Layout
Constructs a layout by reading it from the specified file.static final Layout
fromInputStream
(InputStream inputStream) Constructs a layout by reading it from the specified input stream.final Layout
Returns the layout with the specified key.final Layout
getLayoutByQualKey
(String qualKey) Returns the layout with the specified qualified key.final Layout
getLayoutByQualKey
(String qualKey, char separator) Returns the layout with the specified qualified key, the keys separated by the specified separator character.final Layout.Seq
Returns the sequence with the specified key.final Layout.Seq
getSeqByQualKey
(String qualKey) Returns the sequence with the specified qualified key.final Layout.Seq
getSeqByQualKey
(String qualKey, char separator) Returns the sequence with the specified qualified key, the keys separated by the specified separator character.final String
Returns the string with the specified key.final String
getStringByQualKey
(String qualKey) Returns the string with the specified qualified key.final String
getStringByQualKey
(String qualKey, char separator) Returns the string with the specified qualified key, the keys separated by the specified separator character.final String
indent()
Returns the indentation discovered in the file or input stream when this layout was constructed with thefromFile(java.nio.file.Path)
orfromInputStream(java.io.InputStream)
factory method, respectively.final Layout
Removes the entry with the specified key.final Layout
Replaces the stored layout having the specified key with the specified layout.final Layout
replace
(String key, Layout.Seq seq) Replaces the stored sequence having the specified key with the specified sequence.final Layout
Replaces the stored string value having the specified key with the specified string value.final Layout
replaceKey
(String key, String newKey) Replaces the specified current key with the specified new key.final void
save()
Invokes thetoFile(java.nio.file.Path, java.lang.String, java.nio.file.OpenOption...)
method with the file identical to thefile
argument of thefromFile(java.nio.file.Path)
factory method and with no open options.final int
size()
Returns the number of entries in this layout.final void
toFile
(Path file, String indent, OpenOption... options) Writes this layout to the specified file.toMap()
Converts this layout to anunmodifiable
map.final void
toOutputStream
(OutputStream stream, String indent) Writes this layout to the specified output stream.
-
Constructor Details
-
Layout
public Layout()Constructs a new empty layout. -
Layout
Copy constructor. Creates a new layout and deeply copies the elements of the specified layout into it. The created layout is memory independent of the specified layout.- Parameters:
layout
- The layout to copy, not allowed to benull
.- Throws:
NullPointerException
- Iflayout
isnull
.
-
-
Method Details
-
fromFile
public static final Layout fromFile(Path file) throws NullPointerException, IndentationException, DanglingCommentException, IOException Constructs a layout by reading it from the specified file. By convention, the first line of text that does not contain white spaces only and that starts with a (series of) white space(s) defines the indentation. (A white space is a character with a code less than or equal to '\u0020', the code of SPACE U+0020.)Blank lines, hence, lines of text containing white spaces only or even no characters at all are tolerated as well as lines of text ending with white spaces immediately before the
line terminator
. Note, however, that such extra sugar, unlike comments, is not retained when the layout is written back to the same file or to another file or output stream calling thetoFile(java.nio.file.Path, java.lang.String, java.nio.file.OpenOption...)
,save()
ortoOutputStream(java.io.OutputStream, java.lang.String)
method.This method assumes the characters in the file to be coded in UTF-8.
- Parameters:
file
- The file containing the layout, not allowed to benull
.- Returns:
- The layout.
- Throws:
NullPointerException
- Iffile
isnull
.IndentationException
- If a line of text is not properly indented. (See the class description to learn about a line of text that is not properly indented.)DanglingCommentException
- If there exists a comment that is not properly followed or not followed at all by an entry or an element of a sequence.IOException
- If the specified file does not exist or if another I/O error occurs.
-
fromInputStream
public static final Layout fromInputStream(InputStream inputStream) throws NullPointerException, IndentationException, DanglingCommentException, IOException Constructs a layout by reading it from the specified input stream. Apart from reading the layout from a stream rather than from a file invoking this factory method has exactly the same effect as invoking thefromFile(java.nio.file.Path)
factory method.The specified input stream is not closed.
- Parameters:
inputStream
- The input stream from where to read the layout, not allowed to benull
.- Returns:
- The layout, never
null
but may be an empty layout. - Throws:
NullPointerException
- IfinputStream
isnull
.IndentationException
- If a line of text is not properly indented. (See the class description to learn about a line of text that is not properly indented.)DanglingCommentException
- If there exists a comment that is not properly followed or not followed at all by an entry or an element of a sequence.IOException
- If an I/O error occurs.
-
toMap
Converts this layout to anunmodifiable
map. The keys and the values of the returned map are the keys and the values of this layout. The values are of typeString
,Seq
orLayout
.- Returns:
- The layout as an unmodifiable map.
-
entries
Returns the entries of this layout. The entries are sorted in the order of their creation. For example, if this layout was obtained from a file or an input stream then the entries appear in the same order as they were originally read from the input stream or the file.- Returns:
- The sorted array of entries of this layout, never
null
.
-
size
public final int size()Returns the number of entries in this layout.- Returns:
- The number of entries in this layout.
-
contains
Returnstrue
if this layout contains an entry with the specified key.- Parameters:
key
- The key whose presence in the layout is to be tested.- Returns:
- The boolean value
true
if this layout contains an entry with the specified key. - Throws:
NullPointerException
- If the specified key isnull
.
-
getString
public final String getString(String key) throws MissingEntryException, NullPointerException, ClassCastException Returns the string with the specified key.- Parameters:
key
- The key whose associated string is to be returned.- Returns:
- The string with the specified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified key.NullPointerException
- If the specified key isnull
.ClassCastException
- If the stored value with the specified key is not a string.
-
getSeq
public final Layout.Seq getSeq(String key) throws MissingEntryException, NullPointerException, ClassCastException Returns the sequence with the specified key.- Parameters:
key
- The key whose associated sequence is to be returned.- Returns:
- The sequence with the specified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified key.NullPointerException
- If the specified key isnull
.ClassCastException
- If the stored value with the specified key is not a sequence.
-
getLayout
public final Layout getLayout(String key) throws MissingEntryException, NullPointerException, ClassCastException Returns the layout with the specified key.- Parameters:
key
- The key whose associated layout is to be returned.- Returns:
- The layout with the specified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified key.NullPointerException
- If the specified key isnull
.ClassCastException
- If the stored value with the specified key is not a layout.
-
getStringByQualKey
public final String getStringByQualKey(String qualKey) throws MissingEntryException, NullPointerException, ClassCastException Returns the string with the specified qualified key.The result and behaviour of invoking this method is identical to the result and behaviour of invoking the
getStringByQualKey(String, char)
method with a separator character equal to the dot ('.
') character.- Parameters:
qualKey
- The qualified key whose associated string is to be returned.- Returns:
- The string with the specified qualified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified qualified key.NullPointerException
- If the specified qualified key isnull
.ClassCastException
- If the stored value of one of the layout keys of the specified qualified key is not a layout or if the stored value with the last key is not a string.
-
getStringByQualKey
public final String getStringByQualKey(String qualKey, char separator) throws MissingEntryException, NullPointerException, ClassCastException Returns the string with the specified qualified key, the keys separated by the specified separator character.A qualified key denotes a sequence of normal keys where the keys are separated from each other by the specified separator character, as, for instance, in
profession.words.tableClassName
with a separator character equal to the dot ('.
'). All but the last key must map to a layout and are therefore called the layout keys. (In the example above,profession
andwords
are layout keys.)A qualified key not containing the separator character has no layout keys and thus reduces to a normal key.
- Parameters:
qualKey
- The qualified key whose associated string is to be returned.separator
- The separator character.- Returns:
- The string with the specified qualified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified qualified key.NullPointerException
- If the specified qualified key isnull
.ClassCastException
- If the stored value of one of the layout keys of the specified qualified key is not a layout or if the stored value with the last key is not a string.
-
getSeqByQualKey
public final Layout.Seq getSeqByQualKey(String qualKey) throws MissingEntryException, NullPointerException, ClassCastException Returns the sequence with the specified qualified key.The result and behaviour of invoking this method is identical to the result and behaviour of invoking the
getSeqByQualKey(String, char)
method with a separator character equal to the dot ('.
') character.- Parameters:
qualKey
- The qualified key whose associated sequence is to be returned.- Returns:
- The sequence with the specified qualified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified qualified key.NullPointerException
- If the specified qualified key isnull
.ClassCastException
- If the stored value of one of the layout keys of the specified qualified key is not a layout or if the stored value with the last key is not a sequence.
-
getSeqByQualKey
public final Layout.Seq getSeqByQualKey(String qualKey, char separator) throws MissingEntryException, NullPointerException, ClassCastException Returns the sequence with the specified qualified key, the keys separated by the specified separator character.A qualified key denotes a sequence of normal keys where the keys are separated from each other by the specified separator character, as, for instance, in
profession.words.tableClassName
with a separator character equal to the dot ('.
'). All but the last key must map to a layout and are therefore called the layout keys. (In the example above,profession
andwords
are layout keys.)A qualified key not containing the separator character has no layout keys and thus reduces to a normal key.
- Parameters:
qualKey
- The qualified key whose associated sequence is to be returned.separator
- The separator character.- Returns:
- The sequence with the specified qualified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified qualified key.NullPointerException
- If the specified qualified key isnull
.ClassCastException
- If the stored value of one of the layout keys of the specified qualified key is not a layout or if the stored value with the last key is not a sequence.
-
getLayoutByQualKey
public final Layout getLayoutByQualKey(String qualKey) throws MissingEntryException, NullPointerException, ClassCastException Returns the layout with the specified qualified key.The result and behaviour of invoking this method is identical to the result and behaviour of invoking the
getLayoutByQualKey(String, char)
method with a separator character equal to the dot ('.
') character.- Parameters:
qualKey
- The qualified key whose associated layout is to be returned.- Returns:
- The layout with the specified qualified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified qualified key.NullPointerException
- If the specified qualified key isnull
.ClassCastException
- If the stored value of one of the keys of the specified qualified key is not a layout.
-
getLayoutByQualKey
public final Layout getLayoutByQualKey(String qualKey, char separator) throws MissingEntryException, NullPointerException, ClassCastException Returns the layout with the specified qualified key, the keys separated by the specified separator character.A qualified key denotes a sequence of normal keys where the keys are separated from each other by the specified separator character, as, for instance, in
profession.words.tableClassName
with a separator character equal to the dot ('.
'). All but the last key must map to a layout and are therefore called the layout keys. (In the example above,profession
andwords
are layout keys.)A qualified key not containing the separator character has no layout keys and thus reduces to a normal key.
- Parameters:
qualKey
- The qualified key whose associated layout is to be returned.separator
- The separator character.- Returns:
- The layout with the specified qualified key, never
null
. - Throws:
MissingEntryException
- If the layout contains no entry with the specified qualified key.NullPointerException
- If the specified qualified key isnull
.ClassCastException
- If the stored value of one of the keys of the specified qualified key is not a layout.
-
add
public final Layout add(String key, String value) throws IllegalArgumentException, NullPointerException Adds the specified string value with the specified key.- Parameters:
key
- The key with which the specified string value is to be associated.value
- The string value to be associated with the specified key.- Returns:
- This layout.
- Throws:
IllegalArgumentException
- If the layout already contains an entry with the specified key.NullPointerException
- If the specified key or string value isnull
.
-
addSeq
Creates a new sequence, adds it to this layout with the specified key and returns the new sequence.- Parameters:
key
- The key with which the new sequence is to be associated.- Returns:
- The newly created empty sequence, never
null
. - Throws:
IllegalArgumentException
- If the layout already contains an entry with the specified key.NullPointerException
- If the specified key isnull
.
-
add
public final Layout add(String key, Layout.Seq seq) throws IllegalArgumentException, NullPointerException Adds the specified sequence with the specified key.- Parameters:
key
- The key with which the specified sequence is to be associated.seq
- The sequence to be associated with the specified key.- Returns:
- This layout.
- Throws:
IllegalArgumentException
- If the layout already contains an entry with the specified key.NullPointerException
- If the specified key or sequence isnull
.
-
addLayout
Creates a new layout, adds it to this layout with the specified key and returns the new layout.- Parameters:
key
- The key with which the new layout is to be associated.- Returns:
- The newly created empty layout, never
null
. - Throws:
IllegalArgumentException
- If the layout already contains an entry with the specified key.NullPointerException
- If the specified key isnull
.
-
add
public final Layout add(String key, Layout layout) throws IllegalArgumentException, NullPointerException Adds the specified layout with the specified key.- Parameters:
key
- The key with which the specified layout is to be associated.layout
- The layout to be associated with the specified key.- Returns:
- This layout.
- Throws:
IllegalArgumentException
- If the layout already contains an entry with the specified key.NullPointerException
- If the specified key or layout isnull
.
-
replace
public final Layout replace(String key, String value) throws MissingEntryException, NullPointerException, ClassCastException Replaces the stored string value having the specified key with the specified string value.- Parameters:
key
- The key whose value is to be replaced.value
- The string value, not allowed to benull
.- Returns:
- This layout.
- Throws:
MissingEntryException
- If the layout contains no entry with the specified key.NullPointerException
- If the specified key or string value isnull
.ClassCastException
- If the stored value with the specified key is not a string.
-
replace
public final Layout replace(String key, Layout.Seq seq) throws MissingEntryException, NullPointerException, ClassCastException Replaces the stored sequence having the specified key with the specified sequence.- Parameters:
key
- The key whose value is to be replaced.seq
- The sequence, not allowed to benull
.- Returns:
- This layout.
- Throws:
MissingEntryException
- If the layout contains no entry with the specified key.NullPointerException
- If the specified key or sequence isnull
.ClassCastException
- If the stored value with the specified key is not a sequence.
-
replace
public final Layout replace(String key, Layout layout) throws MissingEntryException, NullPointerException, ClassCastException Replaces the stored layout having the specified key with the specified layout.- Parameters:
key
- The key whose value is to be replaced.layout
- The layout, not allowed to benull
.- Returns:
- This layout.
- Throws:
MissingEntryException
- If the layout contains no entry with the specified key.NullPointerException
- If the specified key or layout isnull
.ClassCastException
- If the stored value with the specified key is not a layout.
-
replaceKey
public final Layout replaceKey(String key, String newKey) throws MissingEntryException, IllegalArgumentException, NullPointerException Replaces the specified current key with the specified new key.This method has no effect if the current key is equal to the new key.
- Parameters:
key
- The current key.newKey
- The new key.- Returns:
- This layout.
- Throws:
MissingEntryException
- If the layout contains no entry with the specified current key.IllegalArgumentException
- If the layout already contains an entry with the specified new key.NullPointerException
- If one of the arguments isnull
.
-
remove
Removes the entry with the specified key.- Parameters:
key
- The key whose entry is to be removed.- Returns:
- This layout.
- Throws:
MissingEntryException
- If the layout contains no entry for the specified key.NullPointerException
- If the specified key isnull
.
-
indent
Returns the indentation discovered in the file or input stream when this layout was constructed with thefromFile(java.nio.file.Path)
orfromInputStream(java.io.InputStream)
factory method, respectively.- Returns:
- The indentation, never an empty string.
The value is
null
if the layout was not constructed with one of the factory methods mentioned above or if the layout has no indented elements.
-
toFile
public final void toFile(Path file, String indent, OpenOption... options) throws IllegalArgumentException, NullPointerException, UnsupportedOperationException, IOException Writes this layout to the specified file. Nested layouts and sequences are indented using the specified indentation or the tab character (CHARACTER TABULATION (U+0009)) if the specified indentation isnull
or an empty string. The written layout strictly conforms to the syntax rules given in the class description.The entries of a layout appear in the order of their creation. This guarantees that a layout that was originally read from a file or an input stream (see
fromFile(java.nio.file.Path)
orfromInputStream(java.io.InputStream)
) looks "similar" to the layout later written back to the same file or to another file. Comments are retained. However, blank lines in the original file and the character (or sequence of characters) used for indendation, as well as extra white spaces immediately before the end of a line of text are not retained. Furthermore, the equal character ('=
') in a property is surrounded by a single space character, ignoring any other surrounding sequences of white spaces in the original file or input stream.Uses UTF-8 for character encoding.
This method fails if the file is locked.
- Parameters:
file
- The file to which to write this layout, not allowed to benull
.indent
- The indentation to use for nested layouts ornull
in which case an indentation equal to CHARACTER TABULATION U+0009 is used.options
- The options specifying how the file is opened, see theFiles.write
method description for any details.- Throws:
IllegalArgumentException
- If the specified indentation contains at least one character that is not a white space.NullPointerException
- If the specified file isnull
.UnsupportedOperationException
- If an unsupported option is specified.IOException
- If an I/O error occurs.
-
save
Invokes thetoFile(java.nio.file.Path, java.lang.String, java.nio.file.OpenOption...)
method with the file identical to thefile
argument of thefromFile(java.nio.file.Path)
factory method and with no open options.- Throws:
UnsupportedOperationException
- If this layout was constructed with a constructor different from thefromFile
factory method.IOException
- If an I/O error occurs.
-
toOutputStream
public final void toOutputStream(OutputStream stream, String indent) throws IllegalArgumentException, NullPointerException, IOException Writes this layout to the specified output stream. Apart from writing the layout to a stream rather than to a file invoking this method has exactly the same effect as invoking thetoFile(java.nio.file.Path, java.lang.String, java.nio.file.OpenOption...)
method.The specified output stream is not closed.
- Parameters:
stream
- The output stream to which to write this layout, not allowed to benull
.indent
- The indentation to use for nested layouts ornull
in which case an indentation equal to CHARACTER TABULATION U+0009 is used.- Throws:
IllegalArgumentException
- If the specified indentation contains at least one character that is not a white space.NullPointerException
- If the specified stream isnull
.IOException
- If an I/O error occurs.
-