Index: doc/release-notes.xml
===================================================================
RCS file: /scm/castor/castor/src/doc/release-notes.xml,v
retrieving revision 1.67
diff -u -r1.67 release-notes.xml
--- doc/release-notes.xml 20 Jun 2005 12:00:53 -0000 1.67
+++ doc/release-notes.xml 28 Jun 2005 21:38:22 -0000
@@ -30,6 +30,24 @@
+
+
+
+ Added support for polymorphism.
+
+
+ Werner Guttmann
+ werner.guttmann@gmx.net
+
+
+ Werner Guttmann
+ werner.guttmann@gmx.net
+
+ Werner Guttmann
+ Bug
+ JDO
+ 20050626
+
Complete rewrite of TransactionContext with regards to obejct tracking.
Index: etc/CHANGELOG
===================================================================
RCS file: /scm/castor/castor/src/etc/CHANGELOG,v
retrieving revision 1.230
diff -u -r1.230 CHANGELOG
--- etc/CHANGELOG 20 Jun 2005 12:00:57 -0000 1.230
+++ etc/CHANGELOG 28 Jun 2005 21:38:34 -0000
@@ -2,6 +2,11 @@
Version (CVS)
-------------
+JDO: Fixed bug CASTOR-1018 using contribution from Werner Guttmann[werner.guttmann@gmx.net]
+ Added support for polymorphism.
+ Details: http://jira.codehaus.org/browse/CASTOR-1018
+ (Werner - 20050626)
+
JDO: Fixed bug CASTOR-1085 using contribution from Gregory Block [gblock@ctoforaday.com]
Complete rewrite of TransactionContext with regards to obejct tracking.
Details: http://jira.codehaus.org/browse/CASTOR-1085
Index: main/org/castor/persist/TransactionContext.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/castor/persist/TransactionContext.java,v
retrieving revision 1.1
diff -u -r1.1 TransactionContext.java
--- main/org/castor/persist/TransactionContext.java 20 Jun 2005 12:00:59 -0000 1.1
+++ main/org/castor/persist/TransactionContext.java 28 Jun 2005 21:38:39 -0000
@@ -548,10 +548,10 @@
public synchronized Object load(final LockEngine engine,
final ClassMolder molder,
final Object identity,
- Object objectToBeLoaded,
+ ProposedObject proposedObject,
final AccessMode suggestedAccessMode)
throws ObjectNotFoundException, LockNotGrantedException, PersistenceException {
- return load(engine, molder, identity, objectToBeLoaded,
+ return load(engine, molder, identity, proposedObject,
suggestedAccessMode, null);
}
@@ -571,7 +571,7 @@
* The class persistence molder
* @param identity
* The object's identity
- * @param objectToBeLoaded
+ * @param proposedObject
* The object to fetch (single instance per transaction)
* @param suggestedAccessMode
* The access mode (see {@link AccessMode}) the values in
@@ -590,7 +590,7 @@
public synchronized Object load(final LockEngine engine,
final ClassMolder molder,
final Object identity,
- Object objectToBeLoaded,
+ ProposedObject proposedObject,
final AccessMode suggestedAccessMode,
QueryResults results)
throws ObjectNotFoundException, LockNotGrantedException, PersistenceException {
@@ -605,12 +605,11 @@
// Test that the object to be loaded (which we will fill in) is of an
// appropriate type for our molder.
- if (objectToBeLoaded != null
+ if (proposedObject.getObject() != null
&& !molder.getJavaClass(_db.getClassLoader()).isAssignableFrom(
- objectToBeLoaded.getClass())) {
+ proposedObject.getProposedClass())) {
throw new PersistenceException(Messages.format(
- "persist.typeMismatch", molder.getName(), objectToBeLoaded
- .getClass()));
+ "persist.typeMismatch", molder.getName(), proposedObject.getProposedClass()));
}
oid = new OID(engine, molder, identity);
@@ -627,8 +626,10 @@
// If the object has been loaded, but the instance sugguested to
// be loaded into is not the same as the loaded instance,
// error is reported.
- if (objectToBeLoaded != null
- && objectToBeLoaded != objectInTransaction) {
+
+ // TODO [WG]: could read && propsedObject != objectInTransaction
+ if (proposedObject.getObject() != null
+ && proposedObject.getObject() != objectInTransaction) {
throw new PersistenceException(Messages.format(
"persist.multipleLoad", molder.getName(), identity));
}
@@ -687,13 +688,13 @@
return objectInTransaction;
}
- // Load (or reload) the object through the persistence engine with the
- // requested lock. This might report failure (object no longer exists),
- // hold until a suitable lock is granted (or fail to grant), or
+ // Load (or reload, in case the object is stored in a acache) the object through the
+ // persistence engine with the requested lock. This might report failure (object no
+ // longer exists), hold until a suitable lock is granted (or fail to grant), or
// report error with the persistence engine.
try {
- if (objectToBeLoaded != null) {
- objectInTransaction = objectToBeLoaded;
+ if (proposedObject.getObject() != null) {
+ objectInTransaction = proposedObject.getObject();
} else {
// ssa, multi classloader feature
// ssa, FIXME : No better way to do that ?
@@ -705,15 +706,29 @@
objectInTransaction = molder.newInstance(_db
.getClassLoader());
}
+
+ proposedObject.setProposedClass(objectInTransaction.getClass());
+ proposedObject.setActualClass(objectInTransaction.getClass());
+ proposedObject.setObject(objectInTransaction);
}
_tracker.trackObject(engine, molder, oid, objectInTransaction);
- OID newoid = engine.load(this, oid, objectInTransaction,
+ OID newoid = engine.load(this, oid, proposedObject,
suggestedAccessMode, _lockTimeout, results);
-
- // rehash the object entry, because oid might have changed!
- _tracker.trackOIDChange(objectInTransaction, engine, oid, newoid);
-
+
+ if (proposedObject.isExpanded()) {
+ // Remove old OID from ObjectTracker
+ _tracker.untrackObject(objectInTransaction);
+ // Create new OID
+ OID newOID = new OID(engine, proposedObject.getActualClassMolder(), identity);
+ // Add new OID to ObjectTracker
+ _tracker.trackObject(engine, molder, oid, proposedObject.getObject());
+ objectInTransaction = proposedObject.getObject();
+ } else {
+ // rehash the object entry, because oid might have changed!
+ _tracker.trackOIDChange(objectInTransaction, engine, oid, newoid);
+ }
+
} catch (ObjectNotFoundException except) {
_tracker.untrackObject(objectInTransaction);
throw except;
Index: main/org/exolab/castor/jdo/drivers/ConnectionProxy.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/ConnectionProxy.java,v
retrieving revision 1.1
diff -u -r1.1 ConnectionProxy.java
--- main/org/exolab/castor/jdo/drivers/ConnectionProxy.java 3 May 2005 15:26:47 -0000 1.1
+++ main/org/exolab/castor/jdo/drivers/ConnectionProxy.java 28 Jun 2005 21:38:41 -0000
@@ -22,16 +22,18 @@
*/
public class ConnectionProxy implements java.sql.Connection {
- /**
- * Default calling location, equals 'unknwon'.
- */
+ /** Default calling location, equals 'unknwon'. */
private static final String DEFAULT_CALLED_BY = "unknown";
- /**
- * Jakarta Common Log instance.
- */
+ /** Jakarta Common Log instance. */
private static final Log _log = LogFactory.getLog(ConnectionProxy.class);
+ /** Has property of LocalConfiguration been read? */
+ private static boolean _isConfigured = false;
+
+ /** Should connections been wrapped by a proxy? */
+ private static boolean _useProxies = false;
+
/**
* The JDBC Connection instance to proxy.
*/
@@ -47,15 +49,8 @@
* @param connection The JDBC connection to proxy.
* @return The JDBC connection proxy.
*/
- public static Connection newConnectionProxy (Connection connection) {
- boolean useProxies = Boolean.getBoolean(LocalConfiguration.getInstance().getProperty("org.exolab.castor.persist.useProxies", "true"));
-
- if (useProxies) {
- return new ConnectionProxy (connection, DEFAULT_CALLED_BY);
- }
-
- return connection;
-
+ public static Connection newConnectionProxy(Connection connection) {
+ return newConnectionProxy(connection, DEFAULT_CALLED_BY);
}
/**
@@ -64,8 +59,19 @@
* @param calledBy Name of the class using creating and this proxy class.
* @return The JDBC connection proxy.
*/
- public static ConnectionProxy newConnectionProxy (Connection connection, String calledBy) {
- return new ConnectionProxy (connection, calledBy);
+ public static Connection newConnectionProxy(Connection connection, String calledBy) {
+ if (!_isConfigured) {
+ String propertyValue = LocalConfiguration.getInstance().getProperty(
+ "org.exolab.castor.persist.useProxies", "true");
+ _useProxies = Boolean.valueOf(propertyValue).booleanValue();
+ _isConfigured = true;
+ }
+
+ if (!_useProxies) {
+ return connection;
+ } else {
+ return new ConnectionProxy(connection, calledBy);
+ }
}
/**
Index: main/org/exolab/castor/jdo/drivers/MultiRSCallQuery.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/MultiRSCallQuery.java,v
retrieving revision 1.4
diff -u -r1.4 MultiRSCallQuery.java
--- main/org/exolab/castor/jdo/drivers/MultiRSCallQuery.java 25 Mar 2004 12:31:06 -0000 1.4
+++ main/org/exolab/castor/jdo/drivers/MultiRSCallQuery.java 28 Jun 2005 21:38:41 -0000
@@ -54,6 +54,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.castor.persist.ProposedObject;
import org.exolab.castor.jdo.ObjectNotFoundException;
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.jdo.QueryException;
@@ -235,10 +236,9 @@
}
- public Object fetch(Object[] fields,Object identity) throws ObjectNotFoundException, PersistenceException
- {
- Object stamp = null;
-
+ public Object fetch(ProposedObject proposedObject, Object identity)
+ throws ObjectNotFoundException, PersistenceException {
+ Object[] fields = proposedObject.getFields();
try {
// Load all the fields of the object including one-one relations
// index 0 belongs to the identity
@@ -251,7 +251,7 @@
} catch ( SQLException except ) {
throw new PersistenceException( Messages.format( "persist.nested", except ) );
}
- return stamp;
+ return null;
}
}
Index: main/org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java,v
retrieving revision 1.4
diff -u -r1.4 PostgreSQLCallQuery.java
--- main/org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java 25 Mar 2004 12:32:01 -0000 1.4
+++ main/org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java 28 Jun 2005 21:38:42 -0000
@@ -54,6 +54,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.castor.persist.ProposedObject;
import org.exolab.castor.jdo.ObjectNotFoundException;
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.jdo.QueryException;
@@ -248,12 +249,10 @@
}
- public Object fetch(Object[] fields,Object identity) throws ObjectNotFoundException, PersistenceException
- {
- Object stamp = null;
-
+ public Object fetch(ProposedObject proposedObject, Object identity)
+ throws ObjectNotFoundException, PersistenceException {
+ Object[] fields = proposedObject.getFields();
try {
-
// Load all the fields of the object including one-one relations
// index 0 belongs to the identity
for ( int i = 1 ; i < _sqlTypes.length ; ++i )
@@ -265,7 +264,7 @@
} catch ( SQLException except ) {
throw new PersistenceException( Messages.format( "persist.nested", except ) );
}
- return stamp;
+ return null;
}
}
Index: main/org/exolab/castor/jdo/drivers/PreparedStatementProxy.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/PreparedStatementProxy.java,v
retrieving revision 1.1
diff -u -r1.1 PreparedStatementProxy.java
--- main/org/exolab/castor/jdo/drivers/PreparedStatementProxy.java 3 May 2005 15:26:47 -0000 1.1
+++ main/org/exolab/castor/jdo/drivers/PreparedStatementProxy.java 28 Jun 2005 21:38:43 -0000
@@ -36,34 +36,28 @@
*/
public class PreparedStatementProxy implements PreparedStatement {
- /**
- * Commons logger.
- */
+ /** Commons logger. */
private static final Log log = LogFactory.getLog (PreparedStatementProxy.class);
- /**
- * PreparedStatement to be proxied.
- */
+ /** Has property of LocalConfiguration been read? */
+ private static boolean _isConfigured = false;
+
+ /** Should connections been wrapped by a proxy? */
+ private static boolean _useProxies = false;
+
+ /** PreparedStatement to be proxied. */
private PreparedStatement preparedStatement;
- /**
- * Connection instance associated with this PreparedStatement
- */
+ /** Connection instance associated with this PreparedStatement */
private Connection connection;
- /**
- * SQL Parameter mapping
- */
+ /** SQL Parameter mapping */
private Map parameters = new HashMap();
- /**
- * The SQL statement to be executed
- */
+ /** The SQL statement to be executed */
private String sqlStatement = null;
- /**
- * List of batch statements associated with this instance.
- */
+ /** List of batch statements associated with this instance. */
private List batchStatements = new ArrayList();
/**
@@ -73,14 +67,21 @@
* @param connection JDBC connection
* @return Prepared statement proxy.
*/
- public static PreparedStatement newPreparedStatementProxy (PreparedStatement statement, String sql, Connection connection) {
- boolean useProxies = Boolean.getBoolean(LocalConfiguration.getInstance().getProperty("org.exolab.castor.persist.useProxies", "true"));
+ public static PreparedStatement newPreparedStatementProxy(
+ PreparedStatement statement, String sql, Connection connection) {
+
+ if (!_isConfigured) {
+ String propertyValue = LocalConfiguration.getInstance().getProperty(
+ "org.exolab.castor.persist.useProxies", "true");
+ _useProxies = Boolean.valueOf(propertyValue).booleanValue();
+ _isConfigured = true;
+ }
- if (useProxies) {
- return new PreparedStatementProxy (statement, sql, connection);
- }
-
- return statement;
+ if (!_useProxies) {
+ return statement;
+ } else {
+ return new PreparedStatementProxy(statement, sql, connection);
+ }
}
/**
Index: main/org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java,v
retrieving revision 1.3
diff -u -r1.3 ReturnedRSCallQuery.java
--- main/org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java 25 Mar 2004 12:24:22 -0000 1.3
+++ main/org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java 28 Jun 2005 21:38:44 -0000
@@ -54,6 +54,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.castor.persist.ProposedObject;
import org.exolab.castor.jdo.ObjectNotFoundException;
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.jdo.QueryException;
@@ -228,12 +229,10 @@
}
- public Object fetch(Object[] fields,Object identity) throws ObjectNotFoundException, PersistenceException
- {
- Object stamp = null;
-
+ public Object fetch(ProposedObject proposedObject, Object identity)
+ throws ObjectNotFoundException, PersistenceException {
+ Object[] fields = proposedObject.getFields();
try {
-
// Load all the fields of the object including one-one relations
// index 0 belongs to the identity
for ( int i = 1 ; i < _sqlTypes.length ; ++i )
@@ -245,7 +244,7 @@
} catch ( SQLException except ) {
throw new PersistenceException( Messages.format( "persist.nested", except ) );
}
- return stamp;
+ return null;
}
}
Index: main/org/exolab/castor/jdo/engine/BaseFactory.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/BaseFactory.java,v
retrieving revision 1.3
diff -u -r1.3 BaseFactory.java
--- main/org/exolab/castor/jdo/engine/BaseFactory.java 19 Jan 2004 11:52:47 -0000 1.3
+++ main/org/exolab/castor/jdo/engine/BaseFactory.java 28 Jun 2005 21:38:44 -0000
@@ -47,6 +47,9 @@
package org.exolab.castor.jdo.engine;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.exolab.castor.mapping.ClassDescriptor;
@@ -73,17 +76,27 @@
* Commons Logging instance used for all logging.
*/
private static Log _log = LogFactory.getFactory().getInstance( BaseFactory.class );
+
+ /**
+ * Maps class descriptor to persistence engines ....
+ */
+ private Map classDescriptorToPersistence = new HashMap();
-
- public Persistence getPersistence( ClassDescriptor clsDesc )
- throws MappingException
- {
- if ( ! ( clsDesc instanceof JDOClassDescriptor ) )
- return null;
+ /**
+ * @see org.exolab.castor.persist.spi.PersistenceFactory#getPersistence(org.exolab.castor.mapping.ClassDescriptor)
+ */
+ public Persistence getPersistence(final ClassDescriptor clsDesc) {
+ if (!(clsDesc instanceof JDOClassDescriptor)) { return null; }
+
try {
- return new SQLEngine( (JDOClassDescriptor) clsDesc, this, null);
- } catch ( MappingException except ) {
- _log.fatal( Messages.format( "jdo.fatalException", except ) );
+ Persistence sqlEngine = (SQLEngine) classDescriptorToPersistence.get(clsDesc);
+ if (sqlEngine == null) {
+ sqlEngine = new SQLEngine((JDOClassDescriptor) clsDesc, this, null);
+ classDescriptorToPersistence.put(clsDesc, sqlEngine);
+ }
+ return sqlEngine;
+ } catch (MappingException except) {
+ _log.fatal(Messages.format("jdo.fatalException", except));
return null;
}
}
Index: main/org/exolab/castor/jdo/engine/DatabaseImpl.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/DatabaseImpl.java,v
retrieving revision 1.25
diff -u -r1.25 DatabaseImpl.java
--- main/org/exolab/castor/jdo/engine/DatabaseImpl.java 20 Jun 2005 12:00:55 -0000 1.25
+++ main/org/exolab/castor/jdo/engine/DatabaseImpl.java 28 Jun 2005 21:38:46 -0000
@@ -54,6 +54,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.castor.persist.ProposedObject;
import org.castor.persist.TransactionContext;
import org.exolab.castor.jdo.*;
import org.exolab.castor.mapping.AccessMode;
@@ -343,7 +344,8 @@
TransactionContext tx = getTransaction();
PersistenceInfo info = _scope.getPersistenceInfo(type);
- return tx.load(info.engine, info.molder, identity, object, mode);
+ ProposedObject proposedObject = new ProposedObject();
+ return tx.load( info.engine, info.molder, identity, proposedObject, mode );
}
public void create( Object object )
Index: main/org/exolab/castor/jdo/engine/SQLEngine.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/SQLEngine.java,v
retrieving revision 1.31
diff -u -r1.31 SQLEngine.java
--- main/org/exolab/castor/jdo/engine/SQLEngine.java 16 Jun 2005 12:14:28 -0000 1.31
+++ main/org/exolab/castor/jdo/engine/SQLEngine.java 28 Jun 2005 21:38:52 -0000
@@ -49,8 +49,10 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.castor.engine.CounterRef;
+import org.castor.persist.ProposedObject;
import org.exolab.castor.jdo.*;
-import org.exolab.castor.jdo.drivers.PreparedStatementProxy;
import org.exolab.castor.mapping.*;
import org.exolab.castor.mapping.loader.FieldHandlerImpl;
import org.exolab.castor.persist.spi.*;
@@ -117,7 +119,7 @@
private ColumnInfo[] _ids;
private SQLEngine _extends;
-
+
private QueryExpression _sqlFinder;
private PersistenceFactory _factory;
@@ -142,6 +144,16 @@
*/
private boolean hasFieldsToPersist = false;
+ /**
+ * Number of ClassDescriptor that extend this one.
+ */
+ private int _numberOfExtendLevels;
+
+ /**
+ * Collection of all the ClassDescriptor that extend this one (closure)
+ */
+ private Collection _extendingClassDescriptors;
+
SQLEngine( JDOClassDescriptor clsDesc, PersistenceFactory factory, String stampField )
throws MappingException {
@@ -293,6 +305,10 @@
_fields = new FieldInfo[fieldsInfo.size()];
fieldsInfo.copyInto( _fields );
+ // obtain the number of ClassDescriptor that extend this one.
+ _numberOfExtendLevels = numberOfExtendingClassDescriptors(getDescriptor());
+ _extendingClassDescriptors = getDescriptor().getExtendedBy();
+
// iterate through all fields to check whether there is a field
// to persist at all; in the case of extend relationships where no
// additional attributes are defined in the extending class, this
@@ -327,6 +343,10 @@
}
}
+ public Persistence.ColumnInfo[] getColumnInfoForIdentities() {
+ return _ids;
+ }
+
public Persistence.FieldInfo[] getInfo() {
return _fields;
}
@@ -941,7 +961,7 @@
if(_log.isDebugEnabled()) {
_log.debug( Messages.format( "jdo.storing", _clsDesc.getJavaClass().getName(),
- _sqlLoad ) );
+ stmt.toString() ) );
}
// bind the identity to the prepareStatement
@@ -964,15 +984,20 @@
for(int i = 0; i < fields.length; i++){
currentField = toJava(i, 0, res.getObject(_fields[i].columns[0].name));
- if ( currentField != null &&
- _fields[i].tableName.compareTo(_mapTo) == 0 &&
- !original[i].equals(currentField) ) {
- if (numberOfFieldsNotMatching >= 1) {
- enlistFieldsNotMatching.append (", ");
+ if (_fields[i].tableName.compareTo(_mapTo) == 0) {
+ if ((original[i] == null && currentField != null) ||
+ (currentField == null && original[i] != null) ||
+ (original[i] == null && currentField == null)) {
+ enlistFieldsNotMatching.append ("(" + _clsDesc.getJavaClass().getName() + ")." + _fields[i].columns[0].name + ": ");
+ enlistFieldsNotMatching.append ("[" + original[i] + "/" + currentField + "]");
+ } else if (!original[i].equals(currentField) ) {
+ if (numberOfFieldsNotMatching >= 1) {
+ enlistFieldsNotMatching.append (", ");
+ }
+ enlistFieldsNotMatching.append ("(" + _clsDesc.getJavaClass().getName() + ")." + _fields[i].columns[0].name + ": ");
+ enlistFieldsNotMatching.append ("[" + original[i] + "/" + currentField + "]");
+ numberOfFieldsNotMatching++;
}
- enlistFieldsNotMatching.append ("(" + _clsDesc.getJavaClass().getName() + ")." + _fields[i].columns[0].name + ": ");
- enlistFieldsNotMatching.append ("[" + original[i] + "/" + currentField + "]");
- numberOfFieldsNotMatching++;
}
}
throw new ObjectModifiedException( Messages.format("persist.objectModified", _clsDesc.getJavaClass().getName(), identity, enlistFieldsNotMatching.toString()) );
@@ -1106,25 +1131,42 @@
}
- public Object load( Object conn, Object[] fields, Object identity, AccessMode accessMode )
- throws ObjectNotFoundException, PersistenceException {
-
+ /**
+ * Loads the object from persistence storage. This method will load
+ * the object fields from persistence storage based on the object's
+ * identity. This method may return a stamp which can be used at a
+ * later point to determine whether the copy of the object in
+ * persistence storage is newer than the cached copy (see {@link
+ * #store}). If lock is true the object must be
+ * locked in persistence storage to prevent concurrent updates.
+ *
+ * @param conn An open connection
+ * @param fields An Object[] to load field values into
+ * @param identity Identity of the object to load.
+ * @param accessMode The access mode (null equals shared)
+ * @return The object's stamp, or null
+ * @throws ObjectNotFoundException The object was not found in persistent storage
+ * @throws PersistenceException A persistence error occured
+ */
+ public Object load( Object conn, ProposedObject proposedObject, Object identity, AccessMode accessMode )
+ throws ObjectNotFoundException, PersistenceException {
PreparedStatement stmt = null;
ResultSet rs = null;
Object stamp = null;
boolean notNull;
+
+ Object[] fields = proposedObject.getFields();
+
try {
- String sql = ( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad;
- stmt = ( (Connection) conn ).prepareStatement(sql);
-
+ String sqlString = (accessMode == AccessMode.DbLocked) ? _sqlLoadLock : _sqlLoad;
+ stmt = ((Connection) conn).prepareStatement(sqlString);
+
if (_log.isDebugEnabled()) {
- String generatedSQL = ( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad;
-// _log.debug( Messages.format( "jdo.loading", _clsDesc.getJavaClass().getName(), generatedSQL ) );
- _log.debug( Messages.format( "jdo.loading", _clsDesc.getJavaClass().getName(), stmt.toString()) );
+ _log.debug( Messages.format("jdo.loading", _clsDesc.getJavaClass().getName(), stmt.toString()));
}
- int count = 1;
+ int fieldIndex = 1;
// bind the identity of the preparedStatement
if ( identity instanceof Complex ) {
Complex id = (Complex) identity;
@@ -1132,37 +1174,67 @@
throw new PersistenceException( "Size of complex field mismatched! expected: "+_ids.length+" found: "+id.size() );
for ( int i=0; i<_ids.length; i++ )
- stmt.setObject( count++, idToSQL( i, id.get(i) ) );
-
+ stmt.setObject(fieldIndex++, idToSQL(i, id.get(i)));
} else {
if ( _ids.length != 1 )
throw new PersistenceException( "Complex field expected!" );
- stmt.setObject( count++, idToSQL( 0, identity ) );
+ stmt.setObject(fieldIndex++, idToSQL(0, identity));
}
if (_log.isDebugEnabled()) {
_log.debug( Messages.format( "jdo.loading", _clsDesc.getJavaClass().getName(), stmt.toString()) );
}
- // query the object
+ // execute the SQL query
rs = stmt.executeQuery();
if ( ! rs.next() )
throw new ObjectNotFoundException( Messages.format("persist.objectNotFound", _clsDesc.getJavaClass().getName(), identity) );
+ if (_extendingClassDescriptors.size() > 0) {
+ Object[] returnValues =
+ calculateNumberOfFields(_extendingClassDescriptors,
+ _ids.length, _fields.length, _numberOfExtendLevels, rs);
+ JDOClassDescriptor potentialLeafDescriptor = (JDOClassDescriptor) returnValues[0];
+
+ if (potentialLeafDescriptor != null &&
+ !potentialLeafDescriptor.getJavaClass().getName().equals (getDescriptor().getJavaClass().getName())) {
+ Object[] expandedFields = new Object[potentialLeafDescriptor.getFields().length];
+
+ fields = expandedFields;
+ proposedObject.setFields (expandedFields);
+ proposedObject.setActualClass (potentialLeafDescriptor.getJavaClass());
+ proposedObject.setExpanded(true);
+ }
+
+ return null;
+ }
+
// Load all the fields of the object including one-one relations
- count = 1;
+ // index to use during ResultSet.getXXX()
+ int columnIndex = 1;
+ // index in fields[] for storing result of SQLTypes.getObject()
+ fieldIndex = 1;
+ String tableName = null;
+ String tableNameOld = tableName;
Object[] temp = new Object[10]; // assume complex field max at 10
- for ( int i = 0 ; i < _fields.length ; ++i ) {
+ for (int i = 0 ; i < _fields.length ; ++i ) {
+ tableName = _fields[i].tableName;
+ if (!tableName.equals (tableNameOld) && !_fields[i].joined) {
+ columnIndex = columnIndex + _ids.length;
+ }
+
if ( !_fields[i].load )
continue;
if ( !_fields[i].multi ) {
notNull = false;
if ( _fields[i].columns.length == 1 ) {
- fields[i] = toJava( i, 0, SQLTypes.getObject( rs, count++, _fields[i].columns[0].sqlType ) );
+ fields[i] = toJava(i, 0, SQLTypes.getObject(rs, columnIndex++, _fields[i].columns[0].sqlType));
+ fieldIndex++;
} else {
- for ( int j=0; j<_fields[i].columns.length; j++ ) {
- temp[j] = toJava( i, j, SQLTypes.getObject( rs, count++, _fields[i].columns[j].sqlType ) );
+ for (int j = 0; j < _fields[i].columns.length; j++) {
+ temp[j] = toJava(i, j, SQLTypes.getObject(rs, columnIndex++, _fields[i].columns[j].sqlType));
+ fieldIndex++;
if ( temp[j] != null ) {
notNull = true;
}
@@ -1176,11 +1248,12 @@
ArrayList res = new ArrayList();
notNull = false;
for ( int j=0; j<_fields[i].columns.length; j++ ) {
- temp[j] = toJava( i, j, SQLTypes.getObject( rs, count, _fields[i].columns[j].sqlType ) );
+ temp[j] = toJava(i, j, SQLTypes.getObject(rs, columnIndex, _fields[i].columns[j].sqlType));
if ( temp[j] != null ) {
notNull = true;
}
- count++;
+ fieldIndex++;
+ columnIndex++;
}
if ( notNull ) {
if ( _fields[i].columns.length == 1 )
@@ -1190,24 +1263,36 @@
}
fields[i] = res;
}
+
+ tableNameOld = tableName;
}
- while ( rs.next() ) {
- count = 1;
- for ( int i = 0; i < _fields.length ; ++i ) {
- if ( !_fields[i].load )
+ while (rs.next()) {
+ fieldIndex = 1;
+ columnIndex = 1;
+
+ tableName = null;
+ tableNameOld = tableName;
+
+ for (int i = 0; i < _fields.length ; ++i) {
+
+ tableName = _fields[i].tableName;
+ if (!tableName.equals (tableNameOld) && !_fields[i].joined) {
+ columnIndex = columnIndex + _ids.length;
+ }
+
+ if ( !_fields[i].load )
continue;
if ( _fields[i].multi ) {
ArrayList res = (ArrayList)fields[i];
notNull = false;
- for ( int j=0; j<_fields[i].columns.length; j++ ) {
- temp[j] = toJava( i, j, SQLTypes.getObject( rs, count, _fields[i].columns[j].sqlType ) );
- if ( temp[j] != null ) {
- notNull = true;
- }
- count++;
+ for (int j = 0; j < _fields[i].columns.length; j++) {
+ temp[j] = toJava(i, j, SQLTypes.getObject(rs, columnIndex, _fields[i].columns[j].sqlType));
+ if (temp[j] != null) { notNull = true; }
+ columnIndex++;
}
+ fieldIndex++;
if ( notNull ) {
if ( _fields[i].columns.length == 1 ) {
if ( !res.contains( temp[0] ) )
@@ -1219,29 +1304,120 @@
}
}
} else {
- count += _fields[i].columns.length;
+ fieldIndex++;
+ columnIndex += _fields[i].columns.length;
}
+ tableNameOld = tableName;
}
+
+ proposedObject.setFields(fields);
}
} catch ( SQLException except ) {
_log.fatal( Messages.format( "jdo.loadFatal", _type, (( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad ) ), except );
-
- throw new PersistenceException( Messages.format("persist.nested", except), except );
+ throw new PersistenceException(Messages.format("persist.nested", except), except);
} finally {
- try {
- if ( rs != null ) rs.close();
- } catch ( SQLException sqle ) {
- _log.warn("Problem closing JDBC Connection instance", sqle);
+ Utils.closeResultSet(rs);
+ Utils.closeStatement(stmt);
+ }
+ return stamp;
+ }
+
+ private int numberOfExtendingClassDescriptors (JDOClassDescriptor classDescriptor) {
+ int numberOfExtendLevels = 1;
+ JDOClassDescriptor currentClassDescriptor = getDescriptor();
+ while (currentClassDescriptor.getExtends() != null) {
+ currentClassDescriptor = (JDOClassDescriptor) currentClassDescriptor.getExtends();
+ numberOfExtendLevels++;
+ }
+ return numberOfExtendLevels;
+ }
+
+ private Object[] calculateNumberOfFields (Collection extendingClassDescriptors,
+ int numberOfIdentityColumns,
+ int numberOfFields,
+ int numberOfExtendLevels,
+ ResultSet rs)
+ throws SQLException
+ {
+ JDOClassDescriptor potentialLeafDescriptor = null;
+ int suggestedNumberOfFields = numberOfFields;
+ Collection potentialActualClassDescriptor = new LinkedList();
+ int numberOfIdentitiesToAnalyze = 0;
+ addExtendingClassDescriptors(potentialActualClassDescriptor, extendingClassDescriptors);
+
+ JDOClassDescriptor potentialClassDescriptor = null;
+ JDOClassDescriptor potentialClassDescriptorPrevious = null;
+ int initialColumnIndex = numberOfFields + numberOfIdentityColumns * numberOfExtendLevels + 1;
+ int columnIndex = initialColumnIndex;
+ int numberOfExtendingClassDescriptors = 0;
+ for (Iterator iter = potentialActualClassDescriptor.iterator(); iter.hasNext(); ) {
+ potentialClassDescriptor = (JDOClassDescriptor) iter.next();
+ numberOfExtendingClassDescriptors += 1;
+ _log.debug ("Potential extending class descriptor: " + potentialClassDescriptor.getJavaClass().getName());
+ FieldDescriptor[] identityDescriptors = potentialClassDescriptor.getIdentities();
+ boolean isNull = true;
+
+ for (int i = 0; i < identityDescriptors.length; i++) {
+ Object temp;
+ Object[] temps;
+ JDOFieldDescriptor jdoFieldDescriptor = (JDOFieldDescriptor) identityDescriptors[i];
+ if (jdoFieldDescriptor.getSQLName().length == 1 ) {
+ temp = SQLTypes.getObject( rs, columnIndex++, java.sql.Types.JAVA_OBJECT);
+ isNull = (temp == null);
+ } else {
+ temps = new Object[jdoFieldDescriptor.getSQLName().length];
+ for ( int j=0; j 0) {
+ potentialLeafDescriptor = potentialClassDescriptor;
+ suggestedNumberOfFields += potentialClassDescriptor.getFields().length;
+ } else if (!iter.hasNext() && isNull && numberOfIdentitiesToAnalyze > 0){
+ potentialLeafDescriptor = potentialClassDescriptorPrevious;
+ // suggestedNumberOfFields += potentialClassDescriptor.getFields().length;
+ } else {
+ FieldDescriptor[] potentialFields =
+ (FieldDescriptor[]) potentialClassDescriptor.getFields();
+ for (int i = 0; i < potentialFields.length; i++) {
+ JDOFieldDescriptor jdoFieldDescriptor = (JDOFieldDescriptor) potentialFields[i];
+ String[] columnNames = jdoFieldDescriptor.getSQLName();
+ columnIndex = columnIndex + columnNames.length;
+ }
+
+ // the JDOClassDescriptor we just looked at is definitely part of the extends hierarchy,
+ // and as such we need to increase the number of potential fields
+ if (!isNull) {
+ suggestedNumberOfFields += potentialClassDescriptor.getFields().length;
+ }
}
}
- return stamp;
+
+ _log.debug ("In total " + numberOfIdentitiesToAnalyze + " (extending) identities analyzed.");
+
+ if ((potentialLeafDescriptor != null) && _log.isDebugEnabled()) {
+ _log.debug ("Most likely of type " + potentialLeafDescriptor.getJavaClass().getName());
+ _log.debug ("After analysis, " + suggestedNumberOfFields + " fields need to be loaded.");
+ }
+
+ return new Object[] {potentialLeafDescriptor, new Integer (suggestedNumberOfFields) };
+
}
-
private void buildSqlCreate () throws QueryException {
StringBuffer sql;
@@ -1399,7 +1575,7 @@
}
- private void buildFinder( JDOClassDescriptor clsDesc ) throws QueryException {
+ private void buildFinder(JDOClassDescriptor clsDesc) throws QueryException {
QueryExpression expr;
QueryExpression find;
@@ -1427,14 +1603,27 @@
baseDesc.getTableName(), baseDesc.getIdentityColumnNames());
curDesc = baseDesc;
}
- for ( int i=0; i<_ids.length; i++ ) {
- find.addColumn( _mapTo, idnames[i] );
- }
-
+
// join all the related/depended table
Vector joinTables = new Vector();
- for ( int i=0; i<_fields.length; i++ ) {
- String alias = _fields[i].tableName;
+ String aliasOld = null;
+ String alias = null;
+
+ for (int i = 0; i < _fields.length; i++) {
+ if (i > 0) { aliasOld = alias; }
+ alias = _fields[i].tableName;
+
+ // add id columns to select statement
+ if (!alias.equals(aliasOld) && !_fields[i].joined) {
+ JDOClassDescriptor classDescriptor = (JDOClassDescriptor)
+ _fields[i].fieldDescriptor.getContainingClassDescriptor();
+ String[] ids = classDescriptor.getIdentityColumnNames();
+ for (int j = 0; j < ids.length; j++) {
+ expr.addColumn(alias, ids[j]);
+ find.addColumn(alias, ids[j]);
+ }
+ }
+
if ( _fields[i].load ) {
if ( _fields[i].joined /*&& !joinTables.contains( _fields[i].tableName )*/ ) {
int offset = 0;
@@ -1458,20 +1647,93 @@
expr.addColumn( alias, _fields[i].columns[j].name );
find.addColumn( alias, _fields[i].columns[j].name );
}
+
expr.addTable(_fields[i].tableName, alias);
find.addTable(_fields[i].tableName, alias);
}
}
+
+ // 'join' all the extending tables
+ curDesc = clsDesc;
+ List classDescriptorsToAdd = new LinkedList();
+ JDOClassDescriptor classDescriptor = null;
+ addExtendingClassDescriptors(classDescriptorsToAdd, curDesc.getExtendedBy());
+
+ if (classDescriptorsToAdd.size() > 0) {
+ for (Iterator iter = classDescriptorsToAdd.iterator(); iter.hasNext(); ) {
+ classDescriptor = (JDOClassDescriptor) iter.next();
+
+ if (_log.isDebugEnabled()) {
+ _log.debug("Adding outer left join for " + classDescriptor.getJavaClass().getName() +
+ " on table " + classDescriptor.getTableName());
+ }
+
+ expr.addOuterJoin( _mapTo,
+ curDesc.getIdentityColumnNames(),
+ classDescriptor.getTableName(),
+ classDescriptor.getIdentityColumnNames());
+ find.addOuterJoin( _mapTo,
+ curDesc.getIdentityColumnNames(),
+ classDescriptor.getTableName(),
+ classDescriptor.getIdentityColumnNames());
+
+ Persistence persistenceEngine;
+ try {
+ persistenceEngine = _factory.getPersistence (classDescriptor);
+ } catch (MappingException e) {
+ throw new QueryException("Problem obtaining persistence engine for ClassDescriptor " + classDescriptor.getJavaClass().getName(), e);
+ }
+
+ SQLEngine.ColumnInfo[] idInfos =
+ (SQLEngine.ColumnInfo[]) persistenceEngine.getColumnInfoForIdentities();
+ for (int i = 0; i < idInfos.length; i++) {
+ expr.addColumn (classDescriptor.getTableName(), idInfos[i].name);
+ find.addColumn (classDescriptor.getTableName(), idInfos[i].name);
+ }
+
+ SQLEngine.FieldInfo[] fieldInfos = (SQLEngine.FieldInfo[]) persistenceEngine.getInfo();
+ for (int i = 0; i < fieldInfos.length; i++) {
+ boolean hasFieldToAdd = false;
+ SQLEngine.ColumnInfo[] columnInfos = fieldInfos[i].columns;
+ if (classDescriptor.getTableName().equals(fieldInfos[i].tableName)) {
+ for ( int j = 0; j < columnInfos.length; j++ ) {
+ expr.addColumn (classDescriptor.getTableName(), fieldInfos[i].columns[j].name);
+ find.addColumn (classDescriptor.getTableName(), fieldInfos[i].columns[j].name);
+ }
+ hasFieldToAdd = true;
+ }
+
+ if (hasFieldToAdd) {
+ expr.addTable(classDescriptor.getTableName());
+ find.addTable(classDescriptor.getTableName());
+ }
+ }
+ }
+ }
+
+
_sqlLoad = expr.getStatement( false );
_sqlLoadLock = expr.getStatement( true );
_sqlFinder = find;
if(_log.isDebugEnabled()) {
- _log.debug( Messages.format( "jdo.loading", _type, _sqlLoad ) );
+ _log.debug(Messages.format("jdo.loading", _type, _sqlLoad));
+ _log.debug(Messages.format("jdo.loading.with.lock", _type, _sqlLoadLock));
+ _log.debug(Messages.format("jdo.finding", _type, _sqlFinder));
}
}
+
+ private void addExtendingClassDescriptors (Collection classDescriptorsToAdd, Collection extendingClassDescriptors) {
+ JDOClassDescriptor classDescriptor = null;
+ for (Iterator iter = extendingClassDescriptors.iterator(); iter.hasNext(); ) {
+ classDescriptor = (JDOClassDescriptor) iter.next();
+ classDescriptorsToAdd.add (classDescriptor);
+ addExtendingClassDescriptors(classDescriptorsToAdd, classDescriptor.getExtendedBy());
+ }
+
+ }
public String toString() {
@@ -1497,10 +1759,18 @@
final String[] joinFields;
ColumnInfo[] columns;
+
+ final FieldDescriptor fieldDescriptor;
+
+ final ClassDescriptor classDescriptor;
FieldInfo( JDOClassDescriptor clsDesc, FieldDescriptor fieldDesc, String classTable, boolean ext )
throws MappingException{
+ fieldDescriptor = fieldDesc;
+
+ classDescriptor = clsDesc;
+
// for readability
final int FIELD_TYPE = 0;
@@ -1645,16 +1915,31 @@
}
}
- static final class ColumnInfo {
+ static final class ColumnInfo implements Persistence.ColumnInfo{
+ /**
+ * Name of the column
+ */
final String name;
+ /**
+ * SQL type of teh coplumn
+ */
final int sqlType;
+ /**
+ * TypeConvertor to use when converting to the SQLType of this column.
+ */
final TypeConvertor convertTo;
+ /**
+ * TypeConvertor to use when converting from the SQLType of this column.
+ */
final TypeConvertor convertFrom;
+ /**
+ * Type conversion parameters
+ */
final String convertParam;
ColumnInfo( String name, int type, TypeConvertor convertTo,
@@ -1665,6 +1950,41 @@
this.convertFrom = convertFrom;
this.convertParam = convertParam;
}
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getName()
+ */
+ public String getName() {
+ return name;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getSqlType()
+ */
+ public int getSqlType() {
+ return sqlType;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getConvertTo()
+ */
+ public TypeConvertor getConvertTo() {
+ return convertTo;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getConvertFrom()
+ */
+ public TypeConvertor getConvertFrom() {
+ return convertFrom;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getConvertParam()
+ */
+ public String getConvertParam() {
+ return convertParam;
+ }
}
static final class SQLQuery implements PersistenceQuery {
@@ -1673,7 +1993,8 @@
private ResultSet _rs;
- private final SQLEngine _engine;
+ private /*final*/ SQLEngine _engine;
+ private SQLEngine _requestedEngine;
private final Class[] _types;
@@ -1692,6 +2013,7 @@
SQLQuery( SQLEngine engine, String sql, Class[] types )
{
_engine = engine;
+ _requestedEngine = engine;
_types = types;
_values = new Object[ _types.length ];
_sql = sql;
@@ -1749,7 +2071,7 @@
}
catch (SQLException e)
{
- throw new PersistenceException(e.getMessage());
+ throw new PersistenceException(e.getMessage(), e);
}
return retval;
}
@@ -1956,19 +2278,36 @@
}
- private Object loadSingleField( int i, int count ) throws SQLException, PersistenceException
- {
+ private Object loadSingleField(int i, CounterRef counterReference)
+ throws SQLException, PersistenceException {
+ String currentTableName = counterReference.getTableName();
+ int count = counterReference.getCounter();
Object[] temp = new Object[_engine._fields[i].columns.length];
boolean notNull = false;
Object field;
+
+ String fieldTableName = _engine._fields[i].tableName;
+
+ ResultSetMetaData metaData = _rs.getMetaData();
+ String columnTableName = metaData.getTableName(count);
+
+ while (!columnTableName.equalsIgnoreCase(fieldTableName)) {
+ count++;
+ columnTableName = metaData.getTableName(count);
+ }
+ String firstColumnOfField = _engine._fields[i].columns[0].name;
+ while (!metaData.getColumnName(count).equalsIgnoreCase(firstColumnOfField)) {
+ count++;
+ }
+
if ( _engine._fields[i].columns.length == 1 ) {
- field = _engine.toJava( i, 0, SQLTypes.getObject( _rs, count++,
- _engine._fields[i].columns[0].sqlType ) );
+ field = _engine.toJava(i, 0, SQLTypes.getObject(_rs, count, _engine._fields[i].columns[0].sqlType));
+ count++;
} else {
for ( int j=0; j<_engine._fields[i].columns.length; j++ ) {
- temp[j] = _engine.toJava( i, j, SQLTypes.getObject( _rs, count++,
- _engine._fields[i].columns[j].sqlType ) );
+ temp[j] = _engine.toJava(i, j, SQLTypes.getObject(_rs, count, _engine._fields[i].columns[j].sqlType));
+ count++;
if ( temp[j] != null ) {
notNull = true;
}
@@ -1978,24 +2317,41 @@
else
field = null;
}
+ counterReference.setCounter(count);
+ counterReference.setTableName(currentTableName);
return field;
}
- private Object loadMultiField( int i, int count, Object field ) throws SQLException, PersistenceException
- {
+ private Object loadMultiField(int i, CounterRef counterReference, Object field)
+ throws SQLException, PersistenceException {
+ int count = counterReference.getCounter();
Object[] temp = new Object[_engine._fields[i].columns.length];
boolean notNull = false;
ArrayList res;
+ String fieldTableName = _engine._fields[i].tableName;
+
+ ResultSetMetaData metaData = _rs.getMetaData();
+ String columnTableName = metaData.getTableName(count);
+
+ while (!columnTableName.equalsIgnoreCase(fieldTableName)) {
+ count++;
+ columnTableName = metaData.getTableName(count);
+ }
+
+ String firstColumnOfField = _engine._fields[i].columns[0].name;
+ while (!metaData.getColumnName(count).equalsIgnoreCase(firstColumnOfField)) {
+ count++;
+ }
+
if( field == null )
res = new ArrayList();
else
res = (ArrayList) field;
for ( int j=0; j<_engine._fields[i].columns.length; j++ ) {
- temp[j] = _engine.toJava( i, j,
- SQLTypes.getObject( _rs, count, _engine._fields[i].columns[j].sqlType ) );
+ temp[j] = _engine.toJava(i, j, SQLTypes.getObject(_rs, count, _engine._fields[i].columns[j].sqlType));
if ( temp[j] != null ) {
notNull = true;
}
@@ -2011,27 +2367,41 @@
res.add( com );
}
}
+ counterReference.setCounter(count);
+
return res;
}
-
- private int loadRow( Object[] fields, boolean isFirst ) throws SQLException, PersistenceException
- {
+ private int loadRow(Object[] fields, int numberOfFields, boolean isFirst)
+ throws SQLException, PersistenceException {
int count = _engine._ids.length + 1;
- // Load all the fields.
- for ( int i = 0 ; i < _engine._fields.length ; ++i ) {
- if ( !_engine._fields[i].load )
- continue;
+ String tableName = null;
- if ( _engine._fields[i].multi ) {
- fields[i] = loadMultiField( i, count, fields[i] );
- } else if( isFirst ) {
- // Non-multi fields have to be done one only once, so this is skipped
- // if we have already read the first row.
- fields[i] = loadSingleField( i, count );
+ // TODO: wrong, as it could be that the first field is not part of the root class.
+ if (numberOfFields > 0) {
+ tableName = _engine._fields[0].tableName;
+
+ // Load all the fields.
+ CounterRef counterReference = new CounterRef ();
+ counterReference.setCounter(count);
+ counterReference.setTableName(tableName);
+
+ for ( int i = 0 ; i < numberOfFields ; ++i ) {
+ if (!_engine._fields[i].load) { continue; }
+
+ if ( _engine._fields[i].multi ) {
+ counterReference.setCounter(count);
+ fields[i] = loadMultiField( i, counterReference, fields[i] );
+ count = counterReference.getCounter();
+ } else if( isFirst ) {
+ // Non-multi fields have to be done one only once, so this is skipped
+ // if we have already read the first row.
+ counterReference.setCounter (count);
+ fields[i] = loadSingleField( i, counterReference);
+ count = counterReference.getCounter();
+ }
}
- count += _engine._fields[i].columns.length;
}
return count;
}
@@ -2064,12 +2434,18 @@
}
- // Fill the given fields[] with the "cached" stuff from our _fields[] .
- public Object fetch( Object[] fields, Object identity ) throws ObjectNotFoundException, PersistenceException
- {
+ /**
+ * @see org.exolab.castor.persist.spi.PersistenceQuery#fetch(org.exolab.castor.persist.ProposedObject, java.lang.Object)
+ */
+ public Object fetch(ProposedObject proposedObject, Object identity)
+ throws ObjectNotFoundException, PersistenceException {
+ Object[] fields = proposedObject.getFields();
+
+ // Fill the given fields[] with the "cached" stuff from our _fields[] .
for( int i = 0; i < _fields.length; i++ ) {
fields[i] = _fields[i];
}
+
return null;
}
@@ -2079,7 +2455,40 @@
// maybe we can optimize a little bit here when we have time.
// Instead of creating new Object[] and ArrayList for each
// "multi field" each fetchRaw is called, we might reuse them.
- _fields = new Object[_engine._fields.length];
+
+ SQLEngine oldEngine = null;
+ int originalFieldNumber = _requestedEngine._fields.length;
+ if (_requestedEngine.getDescriptor().isExtended()) {
+ Collection extendingClassDescriptors = _requestedEngine.getDescriptor().getExtendedBy();
+ int numberOfExtendLevels = _requestedEngine.numberOfExtendingClassDescriptors(_requestedEngine.getDescriptor());
+ JDOClassDescriptor leafDescriptor = null;
+ Object[] returnValues = null;
+ try {
+ returnValues =_requestedEngine.calculateNumberOfFields(extendingClassDescriptors, _requestedEngine._ids.length, _requestedEngine._fields.length, numberOfExtendLevels, this._rs);
+ } catch (SQLException e) {
+ _log.error ("Problem calculating number of concrete fields.", e);
+ throw new PersistenceException ("Problem calculating number of concrete fields.", e);
+ }
+
+ leafDescriptor = (JDOClassDescriptor) returnValues[0];
+
+ if (leafDescriptor != null) {
+ if (!leafDescriptor.getJavaClass().getName().equals(_requestedEngine.getDescriptor().getJavaClass().getName())) {
+ originalFieldNumber = ((Integer) returnValues[1]).intValue();
+
+ Persistence newEngine =null;
+ try {
+ newEngine = _requestedEngine._factory.getPersistence(leafDescriptor);
+ } catch (MappingException e) {
+ _log.error ("Problem obtaining persistence engine for " + leafDescriptor.getJavaClass().getName(), e);
+ throw new PersistenceException ("Problem obtaining persistence engine for " + leafDescriptor.getJavaClass().getName(), e);
+ }
+ _engine = (SQLEngine) newEngine;
+ }
+ }
+ }
+
+ _fields = new Object[originalFieldNumber];
// It would prove a little difficult to fetch if we don't have any rows with data left :-)
if ( _resultSetDone )
@@ -2102,7 +2511,7 @@
// As we assume that we have called fetch() immediatly after nextIdentity(),
// we can be sure that it belongs to the object we want. This is probably not the
// safest programming style, but has to suffice currently :-)
- loadRow( _fields, true );
+ loadRow(_fields, originalFieldNumber, true);
// We move forward in the ResultSet, until we see another identity or run out of rows.
while ( _rs.next() ) {
@@ -2114,7 +2523,7 @@
if( identitiesEqual( wantedIdentity, currentIdentity ) ) {
// Load next row of object data from _rs into <_fields> array.
- loadRow( _fields, false );
+ loadRow(_fields, originalFieldNumber, false);
} else {
// We are done with all the rows for our obj. and still have rows left.
@@ -2129,7 +2538,6 @@
// We are done with all the rows for our obj. and don't have any rows left.
_resultSetDone = true;
_lastIdentity = null;
-
} catch ( SQLException except ) {
throw new PersistenceException( Messages.format("persist.nested", except), except );
}
Index: main/org/exolab/castor/jdo/engine/SimpleQueryExecutor.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/SimpleQueryExecutor.java,v
retrieving revision 1.6
diff -u -r1.6 SimpleQueryExecutor.java
--- main/org/exolab/castor/jdo/engine/SimpleQueryExecutor.java 3 May 2005 15:26:47 -0000 1.6
+++ main/org/exolab/castor/jdo/engine/SimpleQueryExecutor.java 28 Jun 2005 21:38:53 -0000
@@ -49,7 +49,6 @@
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.jdo.QueryException;
import org.exolab.castor.jdo.QueryResults;
-import org.exolab.castor.jdo.drivers.PreparedStatementProxy;
import org.exolab.castor.persist.spi.QueryExpression;
import org.exolab.castor.util.SqlBindParser;
Index: main/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java,v
retrieving revision 1.2
diff -u -r1.2 ClassDescriptorImpl.java
--- main/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java 5 Mar 2005 13:41:52 -0000 1.2
+++ main/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java 28 Jun 2005 21:38:54 -0000
@@ -47,6 +47,12 @@
package org.exolab.castor.mapping.loader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.exolab.castor.mapping.ValidityException;
import org.exolab.castor.mapping.ClassDescriptor;
import org.exolab.castor.mapping.FieldDescriptor;
@@ -66,9 +72,9 @@
public class ClassDescriptorImpl
implements ClassDescriptor
{
+ private static final Log _log = LogFactory.getLog(ClassDescriptorImpl.class);
-
- private ClassMapping _map;
+ private ClassMapping _map;
/**
* The Java class for this descriptor.
*/
@@ -85,11 +91,15 @@
* or null if this is a top-level class.
*/
private final ClassDescriptor _extends;
-
+
+ /**
+ * A collection of class descriptors that extend this class, or
+ * an empty collection if this is a leaf class.
+ */
+ private final Collection _extendedBy = new LinkedList();
private final ClassDescriptor _depends;
-
/**
* The field of the identity for this class.
*/
@@ -166,6 +176,12 @@
throw new MappingException( "mapping.classDoesNotExtend",
_javaClass.getName(), extend.getJavaClass().getName() );
_extends = extend;
+
+ if ( _extends.getClass().getName().equals("org.exolab.castor.jdo.engine.JDOClassDescriptor") &&
+ this.getClass().getName().equals("org.exolab.castor.jdo.engine.JDOClassDescriptor")) {
+ ((ClassDescriptorImpl) _extends).addExtendedBy(this);
+ }
+
if ( _extends instanceof ClassDescriptorImpl )
_identities = ( identities == null ? ((ClassDescriptorImpl)_extends).getIdentities() : identities );
else
@@ -232,6 +248,27 @@
public ClassDescriptor getExtends()
{
return _extends;
+ }
+
+ public boolean isExtending() {
+ return (_extends != null);
+ }
+
+ /**
+ * Returns a collection of class descriptors that extend this class descriptor.
+ *
+ * @return A collection of class descriptors.
+ */
+ public Collection getExtendedBy() {
+ return _extendedBy;
+ }
+
+ public boolean isExtended() {
+ return (_extendedBy.size() > 0);
+ }
+
+ public void addExtendedBy(ClassDescriptor classDesc) {
+ _extendedBy.add(classDesc);
}
public ClassDescriptor getDepends() {
Index: main/org/exolab/castor/persist/ClassMolder.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/persist/ClassMolder.java,v
retrieving revision 1.24
diff -u -r1.24 ClassMolder.java
--- main/org/exolab/castor/persist/ClassMolder.java 20 Jun 2005 12:00:50 -0000 1.24
+++ main/org/exolab/castor/persist/ClassMolder.java 28 Jun 2005 21:39:03 -0000
@@ -76,6 +76,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.castor.persist.ProposedObject;
import org.castor.persist.TransactionContext;
import org.exolab.castor.jdo.DuplicateIdentityException;
import org.exolab.castor.jdo.ObjectDeletedException;
@@ -487,17 +489,23 @@
extendFields = getFullFields( extend );
thisFields = clsMap.getFieldMapping();
- fieldList = new ArrayList(extendFields.length + thisFields.length);
+ fieldList = new ArrayList(extendFields.length + thisFields.length - identities.length);
for (int i = 0; i < extendFields.length; i++) {
fieldList.add(extendFields[i]);
}
- for ( int i=0; i -->
-
+
+
+
+
+
@@ -133,7 +137,11 @@
-
+
+
+
+
+
@@ -202,7 +210,11 @@
-
+
+
+
+
+
@@ -269,7 +281,11 @@
-
+
+
+
+
+
@@ -337,7 +353,11 @@
-
+
+
+
+
+
@@ -404,7 +424,11 @@
-
+
+
+
+
+
@@ -471,7 +495,11 @@
-
+
+
+
+
+