Creation
In ChapterDesignwe coded the classes for a sample database. Once the classes have been coded, creating the actual database is just a matter of running a single method of the Setup Tool. But before that, a few preparatory work needs to be done.
The remaining sections of this page are
Preparing the Classes
For the setup tool to run successfully, the database class and the table classes must meet a few requirements. It is worth noting that these requirements only need to be met during the one-time process of creating the database, which means that all changes made for this purpose can be undone afterwards. Such changes are highlighted below.Preparing the Database Class
The following things must be done:-
The class declaration must be annotated with the
@SetupDatabaseannotation. -
All table declarations must be annotated with the
@SetupTableDeclarationannotation.
Design:
@SetupDatabase(
name = "Edu",
tables = { "Course", "Student", "Teacher", "Contact" }
)
final class EduDB extends CustomDatabase {
@SetupTableDeclaration("Course")
static final CourseTable COURSE_TABLE = new CourseTable();
@SetupTableDeclaration("Student")
static final StudentTable STUDENT_TABLE = new StudentTable();
@SetupTableDeclaration("Teacher")
static final TeacherTable TEACHER_TABLE = new TeacherTable();
@SetupTableDeclaration("Contact")
static final ContactTable CONTACT_TABLE = new ContactTable();
EduDB(Path mainFile, int opMode, boolean writeProtect,
int consistencyNumber) {
open(mainFile, opMode, writeProtect, null, consistencyNumber,
COURSE_TABLE, STUDENT_TABLE, TEACHER_TABLE, CONTACT_TABLE);
}
}
Remarks:
-
The name of the database is specified as the value of the
nameelement of the@SetupDatabaseannotation. Besides the requirednameandtableselements, the@SetupDatabaseannotation has an optionalversionelement which we haven't used in this example. -
The name of a table is specified with the
@SetupTableDeclarationannotation. The table names are repeated in thetableselement of the@SetupDatabaseannotation. -
The order of the table names listed in the
tableselement of the@SetupDatabaseannotation must be the same as the order in which the corresponding table variables appear in theopenmethod. (Theopenmethod is invoked in the constructor.)
Preparing the Table Classes
The following things must be done:-
The class declaration must include the
publicaccess level modifier and be annotated with the@SetupTableannotation. -
Each column declaration must include the
publicaccess level modifier and must be annotated with the@SetupColumnannotation. -
The table class must have a
publicno-arg constructor.
Design:
@SetupTable({ "Student Number", "Name", "Contact", "Courses" })
public final class StudentTable extends CustomTable {
@SetupColumn("Student Number")
public static final Column<Integer> STUDENT_NUMBER = CL.ofInteger(NO_NULL);
@SetupColumn("Name")
public static final Column<String> NAME = CL.ofString(NO_NULL, SMALL);
@SetupColumn(value = "Contact", refdTable = "Contact")
public static final Column<Ref> CONTACT = CL.ofRef();
@SetupColumn(value = "Courses", refdTable = "Course")
public static final Column<Ref[]> COURSES = CL.ofArrayOfRef(30);
public StudentTable() {
initialize(STUDENT_NUMBER, NAME, CONTACT, COURSES);
}
}
Remarks:
-
The name of a column is specified with the
@SetupColumnannotation. The column names are repeated in the@SetupTableannotation. -
The order of the column names listed in the
@SetupTableannotation must be the same as the order in which the corresponding column variables appear in theinitializemethod. (Theinitializemethod is invoked in the constructor.) -
The name of the referenced table of a column with a reference type is
specified by the
refdTableelement of the@SetupColumnannotation. Recall that the name of a table is specified as the value of the@SetupTableDeclarationannotation used in the database class.
Creating the Database
InvokingSetup.run(String, Path) creates the database.
The first parameter specifies the qualified name of the database class and
the second the directory where to save the generated database files.
(The database class is the class annotated with the
@SetupDatabase annotation.)
For example, we create our sample database and save it to the dbDir
directory by executing
Setup.run("example.db.EduDB", Paths.get("dbDir"));
If nothing goes wrong a message similar to
INFO: Database "Edu" successfully created and saved to "dbDir".is printed to the standard output stream.
Among the files created in the dbDir
directory you'll find a file
with the name layout
.
The layout file is the main database file of a WR database and contains all
information needed to run the database.
(The WR database type is explained in the next section.)
You can open the layout file with
any text viewer and read it.
The entries are formatted as described in the
Layout class.
Do you recognize the name of the database, the names of its tables and the
names of the tables' columns we just specified in the previous section?
Section Changing Settings
of
Chapter Maintenance
shows you how to
safely change the entries in the layout file.
Creating an RO Database from a WR Database and vice versa
When we speak of an ACDP database we usually mean the writableWRtype. However, there is a second database type, the
ROtype. An RO database is readonly and resides in a highly compacted single file. As will be shown in Chapter
Opening, an RO database can be loaded completely into main memory, provided that enough main memory is available. An application whose data is completely in main memory usually scales better with respect to the number of concurrent read operations compared to an application that has to read data on demand from a secondary memory device.
An RO database stored in a file specified by the first argument of the following method can be created from an open WR database by invoking the
createRO(Path, ICipherFactory)
method from either an instance of a custom database class (a custom database
class inherits this method from the
CustomDatabase class) or of an instance
implementing the
Database interface, depending on whether the database was
opened as a strongly or weakly typed database, respectively.
(In Chapter Openingyou learn how to open a database as a strongly typed or a weakly typed database.)
Specifying a non-null value for the ICipherFactory parameter
results in an encrypted RO database.
ROToWR.run(Path, Path, Path, ICipherFactory)
method of the
ROToWR Tool creates a WR database from an RO database.
Here, the first, second and third parameter are paths that point to the
RO database, the directory of the WR database to be created and the optional
layout file of the WR database the RO database was created from,
respectively.
The cipher factory is used for reading the RO database as well as for writing
the WR database.
Of course, converting to an RO database with a cipher factory that generates an encryption different from that of the WR database and converting back to a WR database results in a copy of the original WR database, but applying a different encryption.