/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

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

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 occurred.
	 */

	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 occurred.
	 */

	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 occurred.
	 */

	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 occurred.
	 */

	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 occurred.
	 */
	
	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(BuildingContext context)
		throws ObjectPoolException;
	public abstract void freeContext(BuildingContext context);
	}


