/* ======================================================================
The Bodington System Software License, Version 1.0
  
Copyright (c) 2001 The University of Leeds.  All rights reserved.
  
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1.  Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2.  Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3.  The end-user documentation included with the redistribution, if any,
must include the following acknowledgement:  "This product includes
software developed by the University of Leeds
(http://www.bodington.org/)."  Alternately, this acknowledgement may
appear in the software itself, if and wherever such third-party
acknowledgements normally appear.

4.  The names "Bodington", "Nathan Bodington", "Bodington System",
"Bodington Open Source Project", and "The University of Leeds" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
d.gardner@leeds.ac.uk.

5.  The name "Bodington" may not appear in the name of products derived
from this software without prior written permission of the University of
Leeds.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO,  TITLE,  THE IMPLIED WARRANTIES 
OF QUALITY  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO 
EVENT SHALL THE UNIVERSITY OF LEEDS OR ITS CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
=========================================================

This software was originally created by the University of Leeds and may contain voluntary 
contributions from others.  For more information on the Bodington Open Source Project, please 
see http://bodington.org/

====================================================================== */

package org.bodington.database;

import org.bodington.server.*;
import org.bodington.pool.*;

import java.sql.*;
import java.util.*;

/**
 * This abstract class must be suclassed to implement a data storage system for
 * BuildingServer.  At runtime BuildingServer will instantiate a storage
 * implementation class.  At present SqlDatabase is the only implementation but
 * there could be implementations for using plain binary file storage or
 * SqlDatabase could be subclassed to cope with peculiar SQL database products.
 * This methods of this class are NOT gnerally called from application
 * objects so this page of documentation is only of interest when programming
 * a subclass.
 * 
 * @author Jon Maber
 * @version 1
 */

public abstract class Database
	{

	/**
	 * This property is not really in use.  It's just a reminded that at 
	 * some point the Database class may need to be in different states.
	 */
	boolean ready=false;

	/**
	 * Stores the next available primary key which will be used next
	 * time a new persistent object is created.
	 */
	static int next_primary_key=0;

	/**
	 * There must be a constructor obviously.
	 * 
	 * @exception java.lang.Exception The database implementation is allowed to throw exceptions when constructing
	 * which will prevent BuildingServer starting.
	 * This constructor calls the init, loadTypes and preloadData methods.
	 */

	public Database()
		throws Exception
		{
		}

	/**
	 * BuildingServer will call the init method after instantiating the
	 * class. Calls {@link #loadTypes()} then {@link #preloadData()}.
	 * 
	 * @exception java.lang.Exception The database can throw an Exception to indicate that it couldn't
	 * initialise.
	 */

	public void init(  Properties properties ) throws Exception
		{
		loadTypes();
		preloadData();
		}

	/**
	 * BuildingServer will call the destroy method when the Database is no longer needed.
	 * 
	 * @exception java.lang.Exception The database can throw an Exception to indicate that it couldn't
	 * initialise.
	 */

	public abstract void destroy();
        

	/**
	 * The database implementation will load up data type information.
	 * @see #init(Properties)
	 * @exception java.lang.Exception The database may indicate that it couldn't load type information by throwing
	 * an Exception.
	 */

	public abstract void loadTypes() throws Exception;

	/**
	 * The database implementation may preload some objects from storage.
	 * @see #init(Properties)
	 * @exception java.lang.Exception The database can indicate a problem preloading data that prevents start up
	 * by throwing an exception.
	 */
	
	public abstract void preloadData() throws Exception;

	/**
	 * Gets a persistent object from store using its primary key to identify it.
	 * If the key is null this must return null without throwing an exception.
	 * This method is not called directly from application code - the find methods
	 * in PersistentObject and its subclasses are more convenient.
	 * 
	 * @param primary_key The primary key of the required object.
	 * @param java_class_name The expected java class.
	 * @return The object or null if it doesn't exist.
	 * @exception org.bodington.server.BuildingServerException If an error other than not finding the object occured.
	 */

	public abstract PersistentObject findPersistentObject( PrimaryKey primary_key, String java_class_name )
		throws BuildingServerException;
	
	/**
	 * Gets a persistent object from store using an index key to identify it.
	 * If the key is null this must return null without throwing an exception.
	 * This method is not called directly from application code - the find methods
	 * in PersistentObject and its subclasses are more convenient.
	 * 
	 * @param index_key The primary key of the required object.
	 * @param java_class_name The expected java class.
	 * @return The object or null if it doesn't exist.
	 * @exception org.bodington.server.BuildingServerException If an error other than not finding the object occured.
	 */

	public abstract PersistentObject findPersistentObject( IndexKey index_key, String java_class_name )
		throws BuildingServerException;
	
	/**
	 * Gets a persistent object from store using an SQL "where" clause.
	 * 
	 * @param where_clause The search specification.
	 * @param java_class_name The expected java class.
	 * @return The object or null if it doesn't exist.
	 * @exception org.bodington.server.BuildingServerException If more than one object matched or another error.
	 */

	public abstract PersistentObject findPersistentObject( String where_clause, String java_class_name )
		throws BuildingServerException;
	

	/**
	 * Gets a set of persistent objects from store using an SQL "where" clause.
	 * 
	 * @param where_clause The search specification.
	 * @param order_by_clause The sort order specification or null.
	 * @param java_class_name The expected java class.
	 * @return The object or null if it doesn't exist.
	 * @exception org.bodington.server.BuildingServerException If errors occured.
	 */

	public abstract Enumeration findPersistentObjects( String where_clause, String order_by_clause, String java_class_name )
		throws BuildingServerException;
	

	/**
	 * Gets a set of primary keys for persistent objects in store using an SQL "where" clause.
	 * 
	 * @param where_clause The search specification.
	 * @param order_by_clause The sort order specification or null.
	 * @param java_class_name The expected java class.
	 * @return The object or null if it doesn't exist.
	 * @exception org.bodington.server.BuildingServerException If errors occured.
	 */

	public abstract Enumeration findPrimaryKeys( String where_clause, String order_by_clause, String java_class_name )
		throws BuildingServerException;
	
	/**
	 * Counts the number of objects using an SQL "where" clause.
	 * 
	 * @param where_clause The search specification.
	 * @param java_class_name The expected java class.
	 * @return The number found.
	 * @exception org.bodington.server.BuildingServerException If errors occured.
	 */
	
	public abstract int countPersistentObjects( String where_clause, String java_class_name )
	throws BuildingServerException;

	/**
	 * Database will save object to database.  Not normally called directly
	 * from application code.
	 * 
	 * @param obj The object to save.
	 * @exception org.bodington.server.BuildingServerException If database error occurs during operation.  Particularly
	 * if object doesn't yet exist in the database.
	 */
	
	public abstract void updateObject( PersistentObject obj ) throws BuildingServerException;

	/**
	 * Used to save a newly instantiated object.  Not normally called directly
	 * from application code.
	 * 
	 * @param obj The object to insert.  Must have a null PrimaryKey which 
	 * will be filled in by this method.
	 * @exception org.bodington.server.BuildingServerException If a database error occurs.
	 */
	
	public abstract void insertObject( PersistentObject obj ) throws BuildingServerException;

	/**
	 * Used to delete an object from the database.  Not normally called directly
	 * from application code.
	 * 
	 * @param obj The object to delete.  Must have a null PrimaryKey which 
	 * will be filled in by this method.
	 * @exception org.bodington.server.BuildingServerException If a database error occurs.
	 */
	
	public abstract void deleteObject( PersistentObject obj ) throws BuildingServerException;

	/**
	 * Creates an object of type PrimaryKey that will be unique
	 * within the storage system of the database.  This method is
	 * implemented here and need not be implemented in the
	 * subclass.  (Although subclass will have to decide on the starting
	 * primary key at start up time.)
	 * 
	 * @return A new unique PrimaryKey object.
	 */
	public synchronized PrimaryKey nextPrimaryKey()
		{
		return new PrimaryKey( next_primary_key++ );
		}

	/**
	 * Used at initialisation time to set the next primary key
	 * value above the range already in use in storage.
	 * 
	 * @param next An instance of PrimaryKey with an internal number higher than
	 * the highest in use in storage.
	 */
	
	public void setNextPrimaryKey( PrimaryKey next )
		{
		next_primary_key=next.intValue();
		}
		
	public abstract void initContext()
		throws ObjectPoolException;
	public abstract void freeContext();
	}


