com.objectwave.persist.broker
Class RDBBroker

java.lang.Object
  |
  +--com.objectwave.persist.AbstractBroker
        |
        +--com.objectwave.persist.broker.RDBBroker
All Implemented Interfaces:
Broker
Direct Known Subclasses:
AccessBroker, FileMakerBroker, HypersonicBroker, OracleBroker

public class RDBBroker
extends AbstractBroker

An implementation of the Broker interface. This implementation is very specific to Relational Database Solutions. Any instances of this class should be obtained from the static getDefaultBroker() method. Special system properties:
ow.persistVerbose
ow.persistMetrics
ow.persistUser
ow.persistPassword
ow.persistDriver
ow.persistConnections
ow.connectUrl
ow.databaseImpl
ow.persistPrepared 'false'
ow.userConnectionPool 'true'
Could use connection per thread ow.exceptionSupportClass A fully qualified class name of a implementation of SQLConvertExceptionIF. The default primaryKeySupport assumes a table called SEQUENCE with a column called nextVal. This approach is prone to race conditions and should be overriden by specific broker instances. The following two SQL statements must be run to generate primary keys.

CREATE TABLE sequence(nextval INTEGER PRIMARY KEY)
INSERT INTO sequence(nextval) VALUES (1000)

Version:
$Id: RDBBroker.java,v 2.11 2002/08/24 16:56:28 dave_hoag Exp $
Author:
Dave Hoag
See Also:
Broker, BrokerFactory

Nested Class Summary
static class RDBBroker.Test
           
 
Field Summary
protected static RDBBroker broker
           
protected  BrokerPropertySource brokerPropertySource
           
protected  boolean connectionPerThread
           
protected  RDBConnectionPool connectionPool
           
protected  ObjectPool pool
           
protected  ProcessResultSet resultEngine
           
protected  SaveObjectsStrategy saveObjectsStrategy
           
protected  SqlModifierBuilder sqlModifyEngine
           
protected  SqlQueryBuilder sqlQueryEngine
           
protected  StatementFactory statementFactory
           
protected  java.lang.ThreadLocal threadLocal
          Used only for connection per thread support.
 
Fields inherited from class com.objectwave.persist.AbstractBroker
exceptionConverter, metrics, props, verbose
 
Constructor Summary
RDBBroker()
           
 
Method Summary
 void beginTransaction()
          If the database supports transactions this method would begin the transaction.
protected  Persistence checkObjectPool(SQLQuery query)
          Checks the object pool for a search done by primary key.
protected  void cleanupSelect(SQLSelect sqlObj, GrinderResultSet resultSet)
          Return the sqlObject to the statementFactory.
 void close()
          A 'closed' RDBBroker will flush it's object pool cache and close all open connections.
 void commit()
          Issues a database Commit.
 void constrainWhereClause(SQLSelect sqlObj, Persistence subject, Persistence p)
          Limit the query to only those instances that exist as foreign keys in the parameter p.
 int count(SQLQuery obj)
          This is the entry point for the find.
 SQLSelect createAttributeSelect(SQLQuery q, java.lang.String[] atts, SQLSelect tempSelect)
          Create the SQLSelect statement for the findAttributes(SQLQuery,String[]) method.
protected  void customizeDetail(BrokerPropertySource propertySource, boolean override)
          Allows subclasses to setup any values they deem necessary prior to any values being fetched from the source.
 RDBBroker defaultBroker()
          This method enables different default brokers.
protected  void defineSelectList(Persistence p, java.lang.String[] paths, SQLSelect sqlObj)
          Modify the sqlObj parameter to contain only those columns specified by the 'paths' parameter.
 void delete(Persistence obj)
          Remove the specified object from the database.
 void deleteAll(SQLQuery obj)
          Delete all objects matching the passed search criteria.
 void deleteObjects(java.util.ArrayList objs)
          Delete all of the objects in the objs collection.
protected  void deleteObjects(java.util.ArrayList objs, int laterListSize)
          We may have several objects to delete.
protected  void determinePrimaryKey(RDBPersistence pObj)
          Sometimes we can not determine the primary key until after the insert has been completed ( MS-Access ).
 void dumpSQLException(java.sql.SQLException ex)
          A SQLException was generated.
 java.lang.Object find(SQLQuery q)
          Find all objects matching the passed search criteria.
 java.util.Vector findAttributes(SQLQuery q, java.lang.String[] atts)
          Used to optimize large queries.
 Pair[] findColumnSqlTypes(SQLQuery query)
          Determine the sql types of each column that will be a part of the query.
protected  CollectionAdapter findResults(SQLQuery obj)
          This is the entry point for the find.
 Persistence findUnique(SQLQuery q)
          Find the one, and only one, object matching the search criteria.
 void finishBuildingQuery(SQLQuery query, SQLSelect sqlObj)
           
protected  void generateInsertValues(RDBPersistence pObj)
          The default behavior is to generate insert values (the primary key ) prior to actually doing the insert.
 BrokerPropertySource getBrokerPropertySource()
          Does not matter if not synchronized, the source object is stateless.
 RDBConnection getConnection()
          Using this method could be VERY dangerous.
static RDBBroker getDefaultBroker()
          Most systems will have only one database broker.
protected  java.lang.String getDefaultDriverName()
          For this broker, the ODBC driver is the default.
protected  PrimaryKeyStrategy getDefaultPrimaryKeyStrategy()
          Default the primary key strategy to the SelectAndUpdate approach.
 ObjectPool getObjectPool()
          Object pool are an in memory cache of database objects.
 RDBPersistence getRDBAdapter(Persistence object)
          A utility method that simplifies code.
 void initConfiguration()
          To determine the values of userName, password, and connectUrl the configuration will first use what the attribute values contain.
 void initialize()
          Normally you would use the 'getDefaultBroker' method.
protected  void initializeConnections()
          Look in the BrokerPropertyIF for a property indicating the number of connections to create.
protected  void initializeConnections(int connectionCount)
          Create the RDBConnections to the database.
protected  void initializeObjectPooling(ObjectPool aPool)
          We are turning on object pooling.
 void insert(RDBPersistence pObj, Persistence obj)
          Builds and executes an insert statement.
static void main(java.lang.String[] args)
          Test method.
protected  RDBConnection newRDBConnection(RDBConnectionPool connectionPool, java.lang.String connectUrl, java.lang.String userName, java.lang.String userPassword)
          Create an RDBConnection instance using the specified configuration.
protected  java.lang.Object nextPrimaryKey(RDBPersistence pObj)
          Do a query to determine the next primary key.
protected  void removeObjectPooling()
          Remove ObjectPoolBrokers from each connection and clear the result engine object pool instance.
 void rollback()
          Issues a database rollback.
 void save(Persistence obj)
          If the object is new we will insert it.
 void saveObjects(java.util.ArrayList objs)
          Save all of the objects in the objs collection.
 void setBrokerPropertySource(BrokerPropertySource source)
          Plug in your own broker property source.
 void setDriver(java.sql.Driver driver)
          When creating a connection use the specified driver.
 void setObjectPool(ObjectPool val)
          Provide the ObjectPool that is to be used for Object Pooling.
 void setUsingObjectPool(boolean value)
          As currently implmented it will preserve the object pool.
 void update(RDBPersistence pObj, Persistence obj)
          Builds and executes an update statement.
 void update(SQLInsert sql, RDBPersistence obj)
          Allow database specific changes to a sqlInsert.
 
Methods inherited from class com.objectwave.persist.AbstractBroker
convertException, convertException, getExceptionConverter, println, setBrokerProperty, setExceptionConverter
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

broker

protected static RDBBroker broker

resultEngine

protected ProcessResultSet resultEngine

sqlQueryEngine

protected SqlQueryBuilder sqlQueryEngine

sqlModifyEngine

protected SqlModifierBuilder sqlModifyEngine

statementFactory

protected StatementFactory statementFactory

saveObjectsStrategy

protected SaveObjectsStrategy saveObjectsStrategy

connectionPool

protected RDBConnectionPool connectionPool

pool

protected ObjectPool pool

connectionPerThread

protected boolean connectionPerThread

threadLocal

protected java.lang.ThreadLocal threadLocal
Used only for connection per thread support.


brokerPropertySource

protected BrokerPropertySource brokerPropertySource
Constructor Detail

RDBBroker

public RDBBroker()
Method Detail

getDefaultBroker

public static RDBBroker getDefaultBroker()
Most systems will have only one database broker. This method is used to support systems of that type. Don't allow multiple threads create multiple brokers.

Returns:
An initialized RDBBroker.

main

public static void main(java.lang.String[] args)
Test method. This will read lines from the file specified. Each line is expected to be a valid SQL statement. Each SQL statement is executed as we enumerate through the lines in the file.

Parameters:
args - java.lang.String[]

setDriver

public void setDriver(java.sql.Driver driver)
               throws java.sql.SQLException
When creating a connection use the specified driver.

Parameters:
driver - The new Driver value
Throws:
java.sql.SQLException
See Also:
#connect

setObjectPool

public void setObjectPool(ObjectPool val)
Provide the ObjectPool that is to be used for Object Pooling.

Parameters:
val - The ObjectPool to use.
See Also:
setUsingObjectPool(boolean)

setUsingObjectPool

public void setUsingObjectPool(boolean value)
As currently implmented it will preserve the object pool. This will also initialize the object pool if one doesn't exist. This method is what actually 'starts' the use of an Object Pool. With out a call to this method, setObjectPool is meaningless.

Parameters:
value - true if this broker is to use an object pool.

setBrokerPropertySource

public void setBrokerPropertySource(BrokerPropertySource source)
Plug in your own broker property source.

Parameters:
source - The new BrokerPropertySource value

getConnection

public RDBConnection getConnection()
Using this method could be VERY dangerous. Lazy initialization of connections allow for easy changing of username , password, and connectUrl.

Returns:
RDBConnection A connection to the database.

getObjectPool

public ObjectPool getObjectPool()
Object pool are an in memory cache of database objects.

Returns:
The ObjectPool value
See Also:
setObjectPool(ObjectPool)

getRDBAdapter

public final RDBPersistence getRDBAdapter(Persistence object)
A utility method that simplifies code.

Parameters:
object -
Returns:
The RDBAdapter value

getBrokerPropertySource

public BrokerPropertySource getBrokerPropertySource()
Does not matter if not synchronized, the source object is stateless.

Returns:
The BrokerPropertySource value

getDefaultDriverName

protected java.lang.String getDefaultDriverName()
For this broker, the ODBC driver is the default. This will be overridden by subclass implementations.

Returns:
java.lang.String

getDefaultPrimaryKeyStrategy

protected PrimaryKeyStrategy getDefaultPrimaryKeyStrategy()
Default the primary key strategy to the SelectAndUpdate approach.

Returns:
The DefaultPrimaryKeyStrategy value

customizeDetail

protected void customizeDetail(BrokerPropertySource propertySource,
                               boolean override)
Allows subclasses to setup any values they deem necessary prior to any values being fetched from the source. Default is to setup defaults several defaults. You can easily extend this by either overriding this method or one of the getDefault methods.

Parameters:
propertySource - The source that will be our 'source' of configuration information
override - Change the values in the propertySource with information from the command line

beginTransaction

public void beginTransaction()
                      throws QueryException
If the database supports transactions this method would begin the transaction.

Throws:
QueryException

commit

public void commit()
            throws QueryException
Issues a database Commit.

Throws:
QueryException

count

public int count(SQLQuery obj)
          throws QueryException
This is the entry point for the find.

Specified by:
count in interface Broker
Overrides:
count in class AbstractBroker
Parameters:
obj - The query object detailing the objects being counted and the constraints of the query.
Returns:
int the number of objects found by the query.
Throws:
QueryException

defaultBroker

public RDBBroker defaultBroker()
This method enables different default brokers. RDBBroker broker = aBrokerClass.newInstance(); broker.defaultBroker(); The return of this method will return either RDBBroker.getDefaultBroker() or, if a subclass was instantiated during the newInstance() call, the return of the subclasses implementation of this method! This allows the instantiation of one broker instance per broker class.

Returns:
com.objectwave.persist.RDBBroker
See Also:
BrokerFactory

delete

public void delete(Persistence obj)
            throws QueryException
Remove the specified object from the database.

Parameters:
obj - The object to delete.
Throws:
QueryException

deleteObjects

public void deleteObjects(java.util.ArrayList objs)
                   throws QueryException
Delete all of the objects in the objs collection. This will attempt to delete objects in an order that makes sense to a relational database.

Specified by:
deleteObjects in interface Broker
Overrides:
deleteObjects in class AbstractBroker
Parameters:
objs - ArrayList of Persistence objects
Throws:
QueryException

dumpSQLException

public void dumpSQLException(java.sql.SQLException ex)
A SQLException was generated. Catch it and display the error information. Note that there could be multiple error objects chained together

Parameters:
ex - The SQLException to display

find

public java.lang.Object find(SQLQuery q)
                      throws QueryException
Find all objects matching the passed search criteria. If none are found an empty array is returned.

Parameters:
q - The query object detailing the object that will be found and the constraints of the query.
Returns:
Most likely a Vector, but it really could be any collection type.
Throws:
QueryException

createAttributeSelect

public SQLSelect createAttributeSelect(SQLQuery q,
                                       java.lang.String[] atts,
                                       SQLSelect tempSelect)
                                throws QueryException
Create the SQLSelect statement for the findAttributes(SQLQuery,String[]) method. Returns the SQLSelect statement to be executed by the RDBConnection. Also called by the com.objectwave.constraints.ConstraintSubselect class to get the sub select statement.

Parameters:
q - - the query object
atts - Array of string denoting path to object attribute. Each entry will correspond to a mapped instance variable. Compound objects can be represeneted by periods in the path. "employee.company.firstName" or "someValue";
tempSelect - - a temporary SQLSelect instance that can be provided to this method to use in building the select statement. Used to minimize object creation. Can be null.
Returns:
SQLSelect - the select statement describing the find attributes query.
Throws:
QueryException
See Also:
findAttributes(SQLQuery, String[]), com.objectwave.persist.constratins.ConstraintSubselect

finishBuildingQuery

public void finishBuildingQuery(SQLQuery query,
                                SQLSelect sqlObj)
Parameters:
query -
sqlObj -

findAttributes

public java.util.Vector findAttributes(SQLQuery q,
                                       java.lang.String[] atts)
                                throws QueryException
Used to optimize large queries. When providing a pick list, we often need very little data. For example: Rather than create, say 800, objects, just return 800 Strings to show the user, and the corresponding primary key field of the object. Once the selection is made, you could then find the Object that was selected.

Parameters:
atts - Array of string denoting path to object attribute. Each entry will correspond to a mapped instance variable. Compound objects can be represeneted by periods in the path. "employee.company.firstName" or "someValue";
q - SQLQuery The details of the request.
Returns:
Vector of Object []. Each Object [] will contain the values for the attribute list.
Throws:
QueryException
See Also:
find(com.objectwave.persist.SQLQuery)

findColumnSqlTypes

public Pair[] findColumnSqlTypes(SQLQuery query)
                          throws QueryException
Determine the sql types of each column that will be a part of the query. This is necessary for prepared statements.

Parameters:
query - The query object detailing the object of the search and the constraints of the query.
Returns:
com.objectwave.utility.Pair []
Throws:
QueryException

deleteAll

public void deleteAll(SQLQuery obj)
               throws QueryException
Delete all objects matching the passed search criteria.

Parameters:
obj - The query object that will make up the where clause of the delete statement.
Throws:
QueryException

findUnique

public Persistence findUnique(SQLQuery q)
                       throws QueryException
Find the one, and only one, object matching the search criteria. If no objects are found, return null.

Parameters:
q - The query object detailing the object that will be found and the constraints of the query.
Returns:
An instance of the subject of the query.
Throws:
QueryException

initConfiguration

public void initConfiguration()
To determine the values of userName, password, and connectUrl the configuration will first use what the attribute values contain. Next it will look to system properties for values. Finally, it will default them to values found here.


initialize

public void initialize()
Normally you would use the 'getDefaultBroker' method. In addition to creating a RDBBroker instance, it will initialize the JDBC Driver and the defaultTransactionLog. This method is public for the ISOLATED instances where it is necessary to create a custom broker. Avoid using this method.

See Also:
com.objectwave.persist.Broker#getDefaultBroker

insert

public void insert(RDBPersistence pObj,
                   Persistence obj)
            throws QueryException,
                   java.sql.SQLException
Builds and executes an insert statement. The primary key is provided and the lastUpdatedTimeStamp is set.

Parameters:
obj - is the object to insert.
pObj -
Throws:
QueryException
java.sql.SQLException

rollback

public void rollback()
              throws QueryException
Issues a database rollback.

Throws:
QueryException

save

public void save(Persistence obj)
          throws QueryException
If the object is new we will insert it. Otherwise an update is performed. The retrieved from database flag will also be set to indicate that it now belongs there.

Parameters:
obj - The peristent object to save.
Throws:
QueryException

saveObjects

public void saveObjects(java.util.ArrayList objs)
                 throws QueryException
Save all of the objects in the objs collection. This will attempt to save objects in an order that makes sense to a relational database.

Parameters:
objs - The peristent objects to save.
Throws:
QueryException

update

public void update(RDBPersistence pObj,
                   Persistence obj)
            throws QueryException,
                   java.sql.SQLException
Builds and executes an update statement.

Parameters:
obj - The object to update.
pObj -
Throws:
QueryException
java.sql.SQLException

close

public void close()
A 'closed' RDBBroker will flush it's object pool cache and close all open connections.

Specified by:
close in interface Broker
Overrides:
close in class AbstractBroker

constrainWhereClause

public void constrainWhereClause(SQLSelect sqlObj,
                                 Persistence subject,
                                 Persistence p)
Limit the query to only those instances that exist as foreign keys in the parameter p.

Parameters:
p - Assumes p has a foreignKey or InstanceLink w/columnName pointer to parameter subject;
subject - The subject of a foreignKey or instanceLink in p;
sqlObj -

update

public void update(SQLInsert sql,
                   RDBPersistence obj)
Allow database specific changes to a sqlInsert. The default case is to add the PrimaryKeyField.

Parameters:
sql - com.objectwave.persist.SQLInsert
obj - com.objectwave.persist.RDBPersistence

initializeObjectPooling

protected void initializeObjectPooling(ObjectPool aPool)
We are turning on object pooling. This will modify each connection to contain an object pool broker pointing to the provided object pool.

Parameters:
aPool -

removeObjectPooling

protected void removeObjectPooling()
Remove ObjectPoolBrokers from each connection and clear the result engine object pool instance. Note: The pool held by this instance is not cleared.


checkObjectPool

protected Persistence checkObjectPool(SQLQuery query)
Checks the object pool for a search done by primary key.

Parameters:
query - defined query
Returns:

defineSelectList

protected void defineSelectList(Persistence p,
                                java.lang.String[] paths,
                                SQLSelect sqlObj)
                         throws QueryException
Modify the sqlObj parameter to contain only those columns specified by the 'paths' parameter.

Parameters:
p - The persistent object
paths - Paths in the object. These will be mapped to DB columns. Only those persistent fields in this object will be found.
sqlObj - The current select object.
Throws:
QueryException
See Also:
findAttributes(com.objectwave.persist.SQLQuery, java.lang.String[])

deleteObjects

protected void deleteObjects(java.util.ArrayList objs,
                             int laterListSize)
                      throws QueryException
We may have several objects to delete. This attempts to delete them in some 'order' that makes sense for a relational database.

Parameters:
objs - A list of persistent objects.
laterListSize -
Throws:
QueryException
See Also:
save(com.objectwave.persist.Persistence)

determinePrimaryKey

protected void determinePrimaryKey(RDBPersistence pObj)
                            throws java.sql.SQLException,
                                   QueryException
Sometimes we can not determine the primary key until after the insert has been completed ( MS-Access ). This is the hook you would use to accomplish this. You must also override generateInsertValues to be a no-op if you are planning on using this approach.

Parameters:
pObj -
Throws:
java.sql.SQLException
QueryException
See Also:
generateInsertValues(com.objectwave.persist.RDBPersistence)

findResults

protected CollectionAdapter findResults(SQLQuery obj)
                                 throws QueryException
This is the entry point for the find.

Parameters:
obj - The query object detailing the object that will be found and the constraints of the query.
Returns:
CollectionAdapter of objects found by the query.
Throws:
QueryException
See Also:
CollectionAdapter

cleanupSelect

protected void cleanupSelect(SQLSelect sqlObj,
                             GrinderResultSet resultSet)
                      throws QueryException
Return the sqlObject to the statementFactory. Close the resultSet. If any errors occur they will be logged and converted to a QueryException

Parameters:
sqlObj -
resultSet -
Throws:
QueryException

generateInsertValues

protected void generateInsertValues(RDBPersistence pObj)
                             throws java.sql.SQLException,
                                    QueryException
The default behavior is to generate insert values (the primary key ) prior to actually doing the insert.

Parameters:
pObj - The source of the data for the insert statement.
Throws:
java.sql.SQLException
QueryException
See Also:
nextPrimaryKey(com.objectwave.persist.RDBPersistence)

initializeConnections

protected void initializeConnections()
Look in the BrokerPropertyIF for a property indicating the number of connections to create. The default number of database connections is one. If the connections have already been created, this method will simply return.

See Also:
AbstractBroker.setBrokerProperty(BrokerPropertyIF), initializeConnections(int)

initializeConnections

protected void initializeConnections(int connectionCount)
Create the RDBConnections to the database.

Parameters:
connectionCount - The number of connections to the relational database.

newRDBConnection

protected RDBConnection newRDBConnection(RDBConnectionPool connectionPool,
                                         java.lang.String connectUrl,
                                         java.lang.String userName,
                                         java.lang.String userPassword)
Create an RDBConnection instance using the specified configuration.

Parameters:
connectionPool -
connectUrl -
userName -
userPassword -
Returns:

nextPrimaryKey

protected java.lang.Object nextPrimaryKey(RDBPersistence pObj)
                                   throws java.sql.SQLException,
                                          QueryException
Do a query to determine the next primary key. This is a VERY unsafe solution and should only be used on databases that don't support other ways of determining pkey.

Parameters:
pObj -
Returns:
Next available primary key field.
Throws:
java.sql.SQLException
QueryException