|
|
|
|
Project 5: SNetDB461
Preface
Many of the facilities mentioned here are implemented in the superclasses of
an SNetDB461. Those superclasses implement a reasonably general, cross-platform
implementation of record-based files; only the SNetDB461 component knows about the
specific format of the SNet tables. This documentation ignores where functionality
is actually implemented, and just talks about what is available from an SNetDB461
object. It also ignores the code in the superclasses intended to provide generality
beyond SNet.
Tables
An SNetDB461 object provides read/write access to two tables, COMMUNITYTABLE
and PHOTOTABLE. The former holds information about community members,
the latter about photos:
Each record of the community table describes a single member of the SNet
community. Records have five fields.
The Name field is a String giving the fully qualified DDNS name
of the member. It is also the key field of the table.
The Generation is an integer, as are the two photo columns; the latter hold the hash of the
photo's data bytes. A value of 0 is used to indicate "none." (It is very unlikely
that some actual photo will hash to 0. It would also be very unfortunate.)
The isFriend field is a boolean, true if the member is a friend,
and false otherwise.
Each record of the photo table describes a single SNet photo.
Records have three fields. The first is an integer giving the hash of the photo's data.
It is alos the key field of table.
The second is an integer count of the number of times this photo appears in the community
table, as either a myPhoto or chosenPhoto entry. It supports garbage collection of
photo table records. Your code is responsible for maintaining the reference count, and for
deleting the record when the count goes to zero.
The final field is a String giving the absolute (full) path name of the local file storing
the photo's bytes. A value of null indicates that there is no local copy.
It is intended that every photo mentioned in the community table should have a record in the
photo table.
It's important to realize that SNetDB461 doesn't really know anything about
the SNet application. It only knows that it has two tables, and what types of
values are stored in the fields of each. This means it never tries to enforce any
application semantics.
Records
SNetDB461 defines a record class for each table. A record object represents
a record of a table.
public class PhotoRecord extends Record {
public int hash;
public int refCount;
public File file;
}
public class CommunityRecord extends Record {
public String name;
public int generation;
public int myPhotoHash;
public int chosenPhotoHash;
public boolean isFriend;
}
All instance variables of each are record type are public,
and it's intended that client code manipulate them directly.
The only public method they support is toString().
Table Operations
SNetDB461 itself provides almost no operations. Instead, table classes
expose methods that allow clients to manipulate them.
SNetDB461 tables provide only very simple operations: read one record, read all records, write one record, and delete a record. The detailed method signatures are given in the
code, but here's a summary.
- Record readOne(key)
If the table contains a record with the given key, it is returned.
Example:
SNetDB461 db = new SNetDB461();
CommunityRecord cRec = db.COMMUNITYTABLE.readOne("foo.cse461.");
PhotoRecord pRec = db.PHOTOTABLE.readOne(1278493845);
- RecordSet<Record> readAll()
Returns all records in the table, as a RecordSet, which is basically
a typed Vector.
Example:
RecordSet<CommunityRecord> cRecVec = db.COMMUNITYTABLE.readAll();
- write(record)
Puts the record in the table, replacing any existing table record containing the same key.
Example:
PhotoRecord pRec = db.PHOTOTABLE.readOne(1278493845);
pRec.generation++;
db.PHOTOTABLE.write(pRec);
- delete(key)
Deletes the table record with the key given in the argument Record.
If there is no such record, does nothing.
Example:
db.PHOTOTABLE.delete(pRec);
You use SNetDB461 mainly by calling methods on the two tables it contains to read a record,
then modify the record in memory, and then write it back. You don't try to modify the tables
directly, using SQL, even if you know SQL and even if the some methods not mentioned here
are public. (Okay, you can do what you want, but there's no support for those things.)
Operations on an SNetDB461 Object
Creation
When you new SNetDB461() it will look for an existing SQLite database
for the SNet application. If it doesn't find one, it will create one.
An SQLite database is simply a file. The name of the file will be
<fullDDNSname>snet.db, e.g., jz.cse461.snet.db.
(Except for the root, the full DDNS name ends with a '.'.)
There's no easy way for the caller to tell if a database already existed or a new one was created.
Because of that, when you create the first SNetDB461 object (e.g., in onCreate())
you should simply call the registerMember(String member)
method mentioned on the main assignment page to make sure the community table
contains records for both the user (whose name is the full DDNS name of the system)
and the root (whose name is the null string).
Using an SNetDB461
SNetDB461 is built on SQLite. In Android, only the thread that opens an
SQLite database can access the database. This means you need to be careful. The
easiest thing to do is to create an SNetDB461 object when you first need
it, use it so long as you're sure the code is being executed by a single thread,
and forget it when that thread returns to the original caller.
The general form of the code is this:
SNetDB461 db = null;
try {
db = new SNetDB461();
...
} finally {
if ( db != null ) db.discard();
}
fixDB()
The only other method provided by the SNetDB461 class
is fixDB(), which applies heuristics that try to bring the tables
into a sensible state. This method understands the meaning of the data in the tables. None
of the other methods do. As mentioned elsewhere in the documentation, it is destructive.
In the worst case, where the tables have become hopelessly confused, find and delete the
file storing the SQLite database. Note that this will reset your own generation number to 0, though,
and so other clients might essentially ignore you until you modify your gallery enough times
to bring your generation number up to a new all-time high (or until you artificially set it high).
The Photo Utility Class
SNetDB461.java also provides a useful utility class, Photo,
not very strongly related
to its main goal (of providing a table abstraction). A Photo object's constructor
takes a Java File object as an argument. The Photo object has
two fields. mPhotoFile is a copy of the constructor's argument. mHash
is the hash value of the file's contents. It's computed automatically when the Photo
object is constructed.
|