com.marringtons.database
Class DAO

java.lang.Object
  extended bycom.marringtons.database.DAO
All Implemented Interfaces:
Closeable, Comparable
Direct Known Subclasses:
Session.PersistentData

public class DAO
extends Object
implements Closeable, Comparable

DAO is the core of the Adze persistent storage mechanism. It is the only class exported from the database package. All database objects inherit from it. All fields that are not static, final or volatile are saved. Objects as well as primative are written to any depth necessary. Strings, Maps, Collections and DAOs are treated specially. A DAO field inside a DAO will be saved as a pointer into the database of the inner field. This makes the objects fully relational. Care must be taken with DAO fields that they are retrieved from the database when the outer DAO is created. They are committed before saving the location. This will cause changes to be recorded on update() or add(). If they are not retrieved from the database nor set as update() or add(), they will not be saved and later retrieved as empty.

Defining a Database Object

Typically create an static inner extending DAO . It is a value object and should have the minimum or no code. If it in turn has inner classes extending Index, they will be used to create hash indexes for the DAO. Names in the Index class must have the same names as fields in the DAO.
 
  static class MyDAO extends DAO
   {
     public int integer; // can contain any form of primative
     public String string; // and Strings
     public MyOtherClass myOtherClass; // and any other class you have defined to any depth
     public HashMap nameValuePairs; // Maps are saved and NVP for more efficient storage
     public DAO anotherDAO; // normalised - committed and saved as a database pointer only
     public ArrayList myList; // as are Collections
     public static class PrimaryIndex extends Index { int integer; String string; }
     public static class SecondaryIndex extends Index( String string; }
   }
  
 

Creating/Attaching to a database

For a simple application with a single database:
 DAO.associateDatabase("db1", false); // in init code - for all access ojects
 // ... and for each DAO as needed ... 
 MyDAO myDAO = new MyDAO(); // will be in the last (or only) database used.
 
 
If the application needs to run multiple databases, the DAO objects need to be associated with the correct database.
 DAO.associateDatabase("dba", true);
 DAO.associate(MyDAO.class, "dba");
 DAO.associate(MyDAO2.class, "dba", 200000);
 
 // DAO.associateDatabase only explicit for read-only
 DAO.associate(TheirDao.class, "dbb");
 DAO.associate(TheirDao2.class, "dbb");
 
 DAO.associate(defaultDao3.class, 10000); // in default database, index 10,000 strong
 
 
Association is not mandatory. If it is not done, the class is associated with the default database for the application. This database is named after the program in the output directory. The index size can be be set directly from properties. When adding a new type of DAO to the system, the database needs a guess on the likely number of records to size the index. This is not a critical requirement. Only if it is 10 times too small will performance degrade perceptibly. Too large a figure will cause some wasted disk space, but again not excessive. This maximum can be specified on the associate() command as above, in the properties file (as indexClassName.indexSize ) or use the default of 1,000,000. To get the required property key, run once without and get the full class name from the log file.

Retrieving Records

 for (
       MyDAO dao = (MyDAO) myDAO.first("my key");
       dao != null;
       dao = (MyDAO) myDAO.next()
     )
 	 processDAO(dao);
 
Method first() has overloaded records to accept an int, String or an Index. The first two look for the first DAO index with one field of type int or String. For more complex indexes, or for any but the first int or String, provide an instance of the index class from your DAO.
 
  MyDAO.PrimaryIndex index = new MyDAO.PrimaryIndex;
  index.integer = 32;
  index.string = "my key";
  if (dao = (MyDAO) myDAO.first( index)) gotIt( dao);
  
 

Adding/Changing/Deleting Records

The DAO system uses an add/update/commit method of operation. update() includes a check that stops the adding of initialised records. It also keeps a copy of the disk based data and compares before doing the physical update.
 MyDAO myDAO = new MyDAO();
 myDAO.update();
 loadMyDAO(myDAO, 1);
 myDAO.commit();
 
 MyDAO dao = myDAO.copy();
 dao.update();
 changeMyDAO(dao, 2);
 dao.commit();
 
update() is mandatory for changing existing records and must be called before changing the data when updating a record.
 MyDAO dao = myDAO.first("test record");
 if (dao == null) dao = defaultDAO.copy();
 dao.update();
 // ...do the normal stuff
 changeMyDAO(dao);
 dao.commit(); // will only write if the dao was actually changed
 
 
The example above will use update() for either depending on whether an existing record is found. Updates can be dropped instead of written to disk by using discard() instead of commit(). The basic system allows duplicate entries. If you have an application with a unique constraint you need to account for that in the code. The above example does this by first searching for a record and only adding it if not found. A commit is done explicitly when a DAO is closed or finalised. The current record can be deleted, along with all indexes.
 if ((dao = myDAO.first("my key")) != null) dao.delete();
 
All DAO based classes implement comparable with super.comparable();

Importing and Exporting Objects

There are times when the objects need to be saved externally, transmitted or represented in an (almost) human readable form. To this end, there are a number of classes that create a HTML representation. If the object is a POJO (not DAO), use the conversion routines in ObjectXML. There are methods to export/import all objects pointed to by an Index (one class) or all objects in a database (all persistent classes). Reader and Writer classes are used for I/O. There are both buffered and unbuffered signatures, so there is no need to buffer the writer before use.
 String xmlRepresentation = dao.toXML();
 MyDAO dao2 = (MyDAO) DAO.fromXML( xmlRepresentation);
 assertTrue( dao.compareTo( dao2) == 0);
 
 // write all of the objects in the database index to a Writer output stream.
 // Outer tag will be name of the database.
 Writer writer = new FileWriter( "MyDAO.xml");
 dao.toXML( writer);	// only the MyDAO objects
 writer.close();

 // write all of the objects in the database to a Writer output stream.
 // Outer tag will be name of the database.
 Writer writer = new FileWriter( "MyDB.xml");
 MyDAO.allToXML( writer);	// all objects in the database (except generated indexes)
 writer.close();
 

Author:
Paul Marrington
See Also:
Index, ObjectXML

Constructor Summary
DAO()
          DAO instantiation.
 
Method Summary
static void allToXML(BufferedWriter writer)
          Scan default database and convert all contained objects to XML.
static void allToXML(BufferedWriter writer, String database)
          Scan a database and convert all contained objects to XML.
static void allToXML(Writer writer)
          Scan default database and convert all contained objects to XML.
static void allToXML(Writer writer, String database)
          Scan a database and convert all contained objects to XML.
static void associate(Class dataClass, int indexSizeEstimate)
          Associate a DAO with the default database.
static void associate(Class dataClass, String databaseName)
          Associate a DAO with a database.
static void associate(Class dataClass, String databaseName, int indexSizeEstimate)
          Associate a DAO with a database.
static com.marringtons.database.DataFile associateDatabase(String name, boolean readOnly)
          Let the DAO system know of databases that will be used by the program.
 void close()
          Close the DAO - writing if dirty.
static void closeDatabases()
          Called before program exits to make sure all systems are flushed.
 void commit()
          Replace existing object with changes (if any are recorded).
 int compareTo(Object that)
          So that DAO value objects can be sorted, added into trees, etc.
 DAO copy()
          Return a copy of a DAO object that can then be added to the database as a new record.
 void delete()
          Delete the current object.
 void discard()
          Discard any changes made to the current object.
 boolean equals(Object object)
          For hashmaps a DAO is equal if it is the same record on disk.
 void finalize()
          Item may be still locked in the cache.
 DAO first(Index index)
          Retrieve the first of a list of objects that match the provided index.
 DAO first(int integerIndex)
          Retrieve the first of a list of objects that match the provided integer index.
 DAO first(String stringIndex)
          Retrieve the first of a list of objects that match the provided string index.
static void flushDatabases()
          Make sure changes on all open databases are committed to disk for perpetuity.
static DAO fromXML(String xml)
          Given an XML string created by toXML(), create an instance of the DAO.
 int hashCode()
          For hashmaps a DAO is equal if it is the same record on disk.
 boolean isActive()
          If the DAO fails to initialise it cannot throw an exception.
static String[] listDatabases()
          Retrieve an array of open databases.
 DAO next()
          Retrieve the next matching record.
static com.marringtons.database.DataFile resetDefaultDatabase()
          All new DAOs after this point will be placed back in the default database.
 String toXML()
          Convert current DAO into an XML string (for display or dump)
 void toXML(BufferedWriter writer)
          Create an XML stream of all objects pointed to by a single index in a single related database.
 void toXML(Writer writer)
          Create an XML stream of all objects pointed to by a single index in a single related database.
 void update()
          Mark an item to save on commit if changed.
 
Methods inherited from class java.lang.Object
getClass, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

DAO

public DAO()
DAO instantiation. Uses prior association with a database or the most recent database association if there was not prior recorded.

Method Detail

resetDefaultDatabase

public static com.marringtons.database.DataFile resetDefaultDatabase()
                                                              throws IOException
All new DAOs after this point will be placed back in the default database. Needed as associateDatabase() will set the specified base as the new default.

Returns:
the default database object.
Throws:
IOException

associateDatabase

public static com.marringtons.database.DataFile associateDatabase(String name,
                                                                  boolean readOnly)
                                                           throws IOException
Let the DAO system know of databases that will be used by the program. associate() can be called directly if this is more convenient.

Parameters:
name - path name of database.
readOnly - true if database for reading only (dictionary).
Returns:
The database associated to.
Throws:
IOException

listDatabases

public static String[] listDatabases()
Retrieve an array of open databases. Typically used to dump or back up database contents.

Returns:
A string array of open databases.

closeDatabases

public static void closeDatabases()
Called before program exits to make sure all systems are flushed.


flushDatabases

public static void flushDatabases()
Make sure changes on all open databases are committed to disk for perpetuity.


associate

public static void associate(Class dataClass,
                             String databaseName)
                      throws IOException
Associate a DAO with a database. If not used the for instance of the DAO created will use the default database. Uses property indexClassName.indexSize or 1,000,000 for the size estimate in creating indexes.

Parameters:
dataClass - class of the object to be persisted in the database.
databaseName - name of database to persist this object class to.
Throws:
IOException

associate

public static void associate(Class dataClass,
                             int indexSizeEstimate)
                      throws IOException
Associate a DAO with the default database.

Parameters:
dataClass - class of the object to be persisted in the database
indexSizeEstimate - a guess on number of records that require indexing.
Throws:
IOException

associate

public static void associate(Class dataClass,
                             String databaseName,
                             int indexSizeEstimate)
                      throws IOException
Associate a DAO with a database. If not used the for instance of the DAO created will use the most recently mentioned database (associate() or associateDatabase()).

Parameters:
dataClass - class of the object to be persisted in the database
databaseName - name of database to persist this object class to.
indexSizeEstimate - as guess on number of records that require indexing.
Throws:
IOException

isActive

public boolean isActive()
If the DAO fails to initialise it cannot throw an exception. Use isActive if you need to check. It is very unlikely to fail and you will get IOException on other activities if it does. Closing a DAO does not deactivate it.

Returns:
true if the DAO is related to a database and ready for use.

close

public void close()
Close the DAO - writing if dirty. Not a true close as the DAO can continue to be used afterwards. It is a requirement for caches and other storage mechanisms.

Specified by:
close in interface Closeable
See Also:
Closeable.close()

first

public DAO first(Index index)
          throws IOException
Retrieve the first of a list of objects that match the provided index. For read-only access list() is more efficient.

Parameters:
index - being inner class of objectClass
Returns:
DAO object or null if not found
Throws:
IOException
See Also:
next()

first

public DAO first(int integerIndex)
          throws IOException
Retrieve the first of a list of objects that match the provided integer index. The indexes are scanned for the first one that holds a single integer - and that one is used. For read-only access list() is more efficient.

Parameters:
integerIndex - integer to key item on.
Returns:
DAO object or null if not found
Throws:
IOException
See Also:
next()

first

public DAO first(String stringIndex)
          throws IOException
Retrieve the first of a list of objects that match the provided string index. The indexes are scanned for the first one that holds a single String - and that one is used. For read-only access list() is more efficient.

Parameters:
stringIndex - string to key item on in index.
Returns:
DAO object or null if not found
Throws:
IOException
See Also:
next()

next

public DAO next()
         throws IOException
Retrieve the next matching record.

Returns:
DAO object or null if no more
Throws:
IOException

copy

public DAO copy()
         throws IOException
Return a copy of a DAO object that can then be added to the database as a new record.

Returns:
a deep copy of the DAO as a new object.
Throws:
IOException

update

public void update()
            throws IOException
Mark an item to save on commit if changed.

Throws:
IOException

commit

public void commit()
            throws IOException
Replace existing object with changes (if any are recorded).

Throws:
IOException

delete

public void delete()
            throws IOException
Delete the current object.

Throws:
IOException

discard

public void discard()
             throws IOException
Discard any changes made to the current object.

Throws:
IOException

finalize

public void finalize()
Item may be still locked in the cache.


equals

public boolean equals(Object object)
For hashmaps a DAO is equal if it is the same record on disk.

Parameters:
object - to compare against.
Returns:
True if they are logically the same.
See Also:
Object.equals(java.lang.Object)

hashCode

public int hashCode()
For hashmaps a DAO is equal if it is the same record on disk.

Returns:
unique code for this item - use the record number.
See Also:
Object.hashCode()

compareTo

public int compareTo(Object that)
So that DAO value objects can be sorted, added into trees, etc.

Specified by:
compareTo in interface Comparable
Parameters:
that - to compare to.
Returns:
-1, 0 or 1.
See Also:
Comparable.compareTo(java.lang.Object)

toXML

public String toXML()
             throws IllegalArgumentException,
                    IllegalAccessException,
                    IOException
Convert current DAO into an XML string (for display or dump)

Returns:
- String containing XML representation of the object
Throws:
IOException
IllegalAccessException
IllegalArgumentException
See Also:
ObjectXML

toXML

public void toXML(Writer writer)
           throws IllegalArgumentException,
                  IOException,
                  IllegalAccessException
Create an XML stream of all objects pointed to by a single index in a single related database. Send it to an unbuffered writer.

Parameters:
writer - stream to write XML to
Throws:
IllegalArgumentException
IOException
IllegalAccessException
See Also:
ObjectXML

toXML

public void toXML(BufferedWriter writer)
           throws IllegalArgumentException,
                  IOException,
                  IllegalAccessException
Create an XML stream of all objects pointed to by a single index in a single related database.

Parameters:
writer - stream to write XML to
Throws:
IllegalArgumentException
IOException
IllegalAccessException
See Also:
ObjectXML

allToXML

public static void allToXML(Writer writer,
                            String database)
                     throws IllegalArgumentException,
                            IOException,
                            IllegalAccessException,
                            InstantiationException
Scan a database and convert all contained objects to XML.

Parameters:
writer - stream to recieve XML text.
database - to scan for objects.
Throws:
InstantiationException
IllegalAccessException
IOException
IllegalArgumentException
See Also:
ObjectXML

allToXML

public static void allToXML(BufferedWriter writer,
                            String database)
                     throws IllegalArgumentException,
                            IOException,
                            IllegalAccessException,
                            InstantiationException
Scan a database and convert all contained objects to XML.

Parameters:
writer - stream to recieve XML text.
database - to scan for objects.
Throws:
InstantiationException
IllegalAccessException
IOException
IllegalArgumentException
See Also:
ObjectXML

allToXML

public static void allToXML(Writer writer)
                     throws IllegalArgumentException,
                            IOException,
                            IllegalAccessException,
                            InstantiationException
Scan default database and convert all contained objects to XML.

Parameters:
writer - stream to recieve XML text.
Throws:
InstantiationException
IllegalAccessException
IOException
IllegalArgumentException
See Also:
ObjectXML

allToXML

public static void allToXML(BufferedWriter writer)
                     throws IllegalArgumentException,
                            IOException,
                            IllegalAccessException,
                            InstantiationException
Scan default database and convert all contained objects to XML.

Parameters:
writer - stream to recieve XML text.
Throws:
InstantiationException
IllegalAccessException
IOException
IllegalArgumentException
See Also:
ObjectXML

fromXML

public static DAO fromXML(String xml)
                   throws ClassNotFoundException,
                          IOException,
                          XMLexception
Given an XML string created by toXML(), create an instance of the DAO. Use this when you have a string containing a single XML rendered object. In most cases use the database load method fromXML( Reader).

Parameters:
xml - string containing valid XML representing an instance of an object descended from DAO.
Returns:
DAO (cast as necessary to specific object class).
Throws:
ClassNotFoundException
IOException
XMLexception
See Also:
ObjectXML


Copyright © 2004 Paul Marrington http://marringtons.com