Revision: 7527
http://datanucleus.svn.sourceforge.net/datanucleus/?rev=7527&view=rev
Author: andy_jefferson
Date: 2009-08-17 13:42:07 +0000 (Mon, 17 Aug 2009)
Log Message:
-----------
Roll back previous until fix issue with persistent interfaces
Modified Paths:
--------------
platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/PersistentIDROF.java
Modified: platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/PersistentIDROF.java
===================================================================
--- platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/PersistentIDROF.java 2009-08-17 13:11:55 UTC (rev 7526)
+++ platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/PersistentIDROF.java 2009-08-17 13:42:07 UTC (rev 7527)
@@ -1,489 +1,473 @@
-/**********************************************************************
-Copyright (c) 2002 Kelly Grizzle (TJDO) and others. All rights reserved.
-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.
-
-
-Contributors:
-2003 Erik Bengtson - removed subclasses operation
-2003 Andy Jefferson - comments, and update to returned class name
-2003 Erik Bengtson - added getObjectByAid
-2004 Erik Bengtson - throws an JDOObjectNotFoundException
-2004 Erik Bengtson - removed unused variable and import
-2004 Erik Bengtson - added support for ignoreCache
-2004 Andy Jefferson - coding standards
-2005 Andy Jefferson - added support for using discriminator to distinguish objects
- ...
-**********************************************************************/
-package org.datanucleus.store.rdbms.query;
-
-import java.lang.reflect.Modifier;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Map;
-
-import org.datanucleus.ClassLoaderResolver;
-import org.datanucleus.FetchPlan;
-import org.datanucleus.ObjectManager;
-import org.datanucleus.StateManager;
-import org.datanucleus.exceptions.NucleusException;
-import org.datanucleus.exceptions.NucleusUserException;
-import org.datanucleus.identity.OID;
-import org.datanucleus.identity.OIDFactory;
-import org.datanucleus.metadata.AbstractClassMetaData;
-import org.datanucleus.metadata.AbstractMemberMetaData;
-import org.datanucleus.metadata.DiscriminatorMetaData;
-import org.datanucleus.metadata.IdentityType;
-import org.datanucleus.metadata.InterfaceMetaData;
-import org.datanucleus.metadata.MetaDataUtils;
-import org.datanucleus.metadata.VersionMetaData;
-import org.datanucleus.store.FieldValues;
-import org.datanucleus.store.fieldmanager.FieldManager;
-import org.datanucleus.store.mapped.MappedStoreManager;
-import org.datanucleus.store.mapped.StatementClassMapping;
-import org.datanucleus.store.mapped.StatementMappingIndex;
-import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
-import org.datanucleus.store.query.ResultObjectFactory;
-import org.datanucleus.store.rdbms.RDBMSStoreManager;
-import org.datanucleus.util.NucleusLogger;
-import org.datanucleus.util.Localiser;
-import org.datanucleus.util.SoftValueMap;
-import org.datanucleus.util.StringUtils;
-
-/**
- * ResultObjectFactory that takes a JDBC ResultSet and create a PersistenceCapable object instance for
- * each row in the ResultSet. We use information in the result set to determine the object type; this
- * can be a discriminator column, or can be a special "NucleusType" column defined just for result
- * processing.
- */
-public final class PersistentIDROF implements ResultObjectFactory
-{
- /** Localiser for messages. */
- protected static final Localiser LOCALISER = Localiser.getInstance(
- "org.datanucleus.store.rdbms.Localisation", RDBMSStoreManager.class.getClassLoader());
-
- /** Metadata for the candidate class. */
- protected final AbstractClassMetaData acmd;
-
- /** Persistent class that this factory will generate (may be the base class). */
- private Class persistentClass;
-
- /** Fetch Plan to use when loading fields (if any). */
- protected final FetchPlan fetchPlan;
-
- /** Whether to ignore the cache */
- private final boolean ignoreCache;
-
- /** Resolved classes for metadata / discriminator keyed by class names. */
- private Map resolvedClasses = new SoftValueMap();
-
- /** Mapping for the statement to members of this class (and sub-objects). */
- final StatementClassMapping classMappingDef;
-
- final int[] classMappedFieldNumbers;
-
- /**
- * Constructor.
- * @param acmd MetaData for the class (base class)
- * @param mappingDefinition Mapping information for the result set and how it maps to the class
- * @param ignoreCache Whether to ignore the cache
- * @param fetchPlan the Fetch Plan
- * @param persistentClass Class that this factory will create instances of (or subclasses)
- */
- public PersistentIDROF(AbstractClassMetaData acmd, StatementClassMapping mappingDefinition,
- boolean ignoreCache, FetchPlan fetchPlan, Class persistentClass)
- {
- if (mappingDefinition == null)
- {
- throw new NucleusException("Attempt to create PersistentIDROF with null mappingDefinition");
- }
-
- this.acmd = acmd;
- this.ignoreCache = ignoreCache;
- this.fetchPlan = fetchPlan;
- this.persistentClass = persistentClass;
-
- // Generate mapping definition information for extracting the object
- int[] fieldNumbers = mappingDefinition.getMemberNumbers();
- if (acmd instanceof InterfaceMetaData)
- {
- // Persistent-interface : create new mapping definition for a result type of the implementation
- classMappingDef = new StatementClassMapping(null);
- classMappingDef.setNucleusTypeColumnName(mappingDefinition.getNucleusTypeColumnName());
- classMappedFieldNumbers = new int[fieldNumbers.length];
- for (int i = 0; i < fieldNumbers.length; i++)
- {
- AbstractMemberMetaData mmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
- classMappedFieldNumbers[i] = acmd.getAbsolutePositionOfMember(mmd.getName());
- classMappingDef.addMappingForMember(classMappedFieldNumbers[i],
- mappingDefinition.getMappingForMemberPosition(fieldNumbers[i]));
- }
- }
- else
- {
- // Persistent class
- classMappingDef = mappingDefinition;
- classMappedFieldNumbers = fieldNumbers;
- }
- }
-
- /**
- * Method to update the persistent class that the result object factory requires.
- * This is used where we have an Extent(BaseClass) and we pass it to a JDOQL query but the query
- * has been specified with a candidate class that is a subclass. So we use this method to restrict
- * the results further.
- * @param cls The Class the result factory requires.
- */
- public void setPersistentClass(Class cls)
- {
- this.persistentClass = cls;
- }
-
- /**
- * Method to convert the current ResultSet row into an Object.
- * @param om The ObjectManager
- * @param rs The ResultSet from the Query.
- * @return The (persisted) object.
- */
- public Object getObject(final ObjectManager om, final Object rs)
- {
- // Find the class of the returned object in this row of the ResultSet
- String className = null;
- boolean requiresInheritanceCheck = true;
- StatementMappingIndex discrimMapIdx = classMappingDef.getMappingForMemberPosition(StatementClassMapping.MEMBER_DISCRIMINATOR);
- if (discrimMapIdx != null)
- {
- // Discriminator mapping registered so use that
- try
- {
- String discrimValue = ((ResultSet)rs).getString(discrimMapIdx.getColumnPositions()[0]);
- JavaTypeMapping discrimMapping = discrimMapIdx.getMapping();
- DiscriminatorMetaData dismd =
- (discrimMapping != null ? discrimMapping.getDatastoreContainer().getDiscriminatorMetaData() : null);
- className = MetaDataUtils.getClassNameFromDiscriminatorValue(discrimValue, dismd, om);
- }
- catch (SQLException sqle)
- {
- NucleusLogger.DATASTORE_RETRIEVE.debug("Exception obtaining value of discriminator : " + sqle.getMessage());
- }
- }
- else if (classMappingDef.getNucleusTypeColumnName() != null)
- {
- // Extract the object type using the NucleusType column (if available)
- try
- {
- className = ((ResultSet)rs).getString(classMappingDef.getNucleusTypeColumnName()).trim();
- }
- catch (SQLException sqle)
- {
- // NucleusType column not found so ignore
- }
- }
-
- ClassLoaderResolver clr = om.getClassLoaderResolver();
- Class pcClassForObject = persistentClass;
- if (className != null)
- {
- Class cls = (Class) resolvedClasses.get(className);
- if (cls != null)
- {
- pcClassForObject = cls;
- }
- else
- {
- if (persistentClass.getName().equals(className))
- {
- pcClassForObject = persistentClass;
- }
- else
- {
- pcClassForObject = clr.classForName(className, persistentClass.getClassLoader());
- }
- resolvedClasses.put(className, pcClassForObject);
- }
- requiresInheritanceCheck = false;
- }
-
- if (identityIsNull(pcClassForObject, (ResultSet)rs, om))
- {
- // Row of resultSet signifies a null object
- // This can happen when doing a LEFT OUTER JOIN and selecting the id of the related object
- return null;
- }
-
- if (Modifier.isAbstract(pcClassForObject.getModifiers()))
- {
- // Persistent class is abstract so we can't create instances of that type!
- // This can happen if the user is using subclass-table and hasn't provided a discriminator in
- // the table. Try going out one level and find a (single) concrete subclass
- // TODO make this more robust and go out further
- String[] subclasses = om.getMetaDataManager().getSubclassesForClass(pcClassForObject.getName(), false);
- if (subclasses != null)
- {
- Class concreteSubclass = null;
- int numConcreteSubclasses = 0;
- for (int i=0;i<subclasses.length;i++)
- {
- Class subcls = clr.classForName(subclasses[i]);
- if (!Modifier.isAbstract(subcls.getModifiers()))
- {
- numConcreteSubclasses++;
- concreteSubclass = subcls;
- }
- }
- if (numConcreteSubclasses == 1)
- {
- // Only one possible subclass, so use that
- pcClassForObject = concreteSubclass;
- NucleusLogger.PERSISTENCE.warn(LOCALISER.msg("052300",
- pcClassForObject.getName(), concreteSubclass.getName()));
- }
- else if (numConcreteSubclasses == 0)
- {
- throw new NucleusUserException(LOCALISER.msg("052301", pcClassForObject.getName()));
- }
- else
- {
- // More than 1 possible so notify the user. Really should return the abstract
- NucleusLogger.PERSISTENCE.warn("Found type=" + pcClassForObject +
- " but abstract and more than 1 concrete subclass (" +
- StringUtils.objectArrayToString(subclasses) + "). Really you need a discriminator" +
- " to help identifying the type. Choosing " + concreteSubclass);
- pcClassForObject = concreteSubclass;
- requiresInheritanceCheck = true;
- }
- }
- }
-
- AbstractClassMetaData cmd = om.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
- if (cmd == null)
- {
- // Should never happen
- return null;
- }
-
- // Extract the object from the ResultSet
- Object obj = null;
- if (cmd.getIdentityType() == IdentityType.APPLICATION)
- {
- obj = getObjectForApplicationId(om, rs, classMappingDef, classMappedFieldNumbers,
- cmd, pcClassForObject, requiresInheritanceCheck);
- }
- else if (cmd.getIdentityType() == IdentityType.DATASTORE)
- {
- // Generate the "oid" for this object (of type pcClassForObject), and find the object for that
- StatementMappingIndex datastoreIdMapping =
- classMappingDef.getMappingForMemberPosition(StatementClassMapping.MEMBER_DATASTORE_ID);
- JavaTypeMapping mapping = datastoreIdMapping.getMapping();
- OID oid = (OID)mapping.getObject(om, rs, datastoreIdMapping.getColumnPositions());
- if (oid != null)
- {
- Object id = oid;
- if (!pcClassForObject.getName().equals(oid.getPcClass()))
- {
- // Get an OID for the right inheritance level
- id = OIDFactory.getInstance(om, pcClassForObject.getName(), oid.getKeyValue());
- }
-
- if (classMappedFieldNumbers == null)
- {
- obj = om.findObject(id, false, requiresInheritanceCheck, null);
- }
- else
- {
- obj = getObjectForDatastoreId(om, rs, classMappingDef, classMappedFieldNumbers,
- cmd, id, requiresInheritanceCheck ? null : pcClassForObject);
- }
- }
- }
- else if (cmd.getIdentityType() == IdentityType.NONDURABLE)
- {
- Object id = om.newObjectId(className, null);
- if (classMappedFieldNumbers == null)
- {
- obj = om.findObject(id, false, requiresInheritanceCheck, null);
- }
- else
- {
- obj = getObjectForDatastoreId(om, rs, classMappingDef, classMappedFieldNumbers,
- cmd, id, pcClassForObject);
- }
- }
-
- if (obj != null)
- {
- // Set the version of the object where possible
- int versionFieldNumber = -1;
- VersionMetaData vermd = cmd.getVersionMetaData();
- if (vermd != null && vermd.getFieldName() != null)
- {
- // Version stored in a normal field
- versionFieldNumber = cmd.getMetaDataForMember(vermd.getFieldName()).getAbsoluteFieldNumber();
- if (classMappingDef.getMappingForMemberPosition(versionFieldNumber) != null)
- {
- StateManager objSM = om.findStateManager(obj);
- Object verFieldValue = objSM.provideField(versionFieldNumber);
- if (verFieldValue != null)
- {
- objSM.setVersion(verFieldValue);
- }
- }
- }
-
- StatementMappingIndex versionMapping =
- classMappingDef.getMappingForMemberPosition(StatementClassMapping.MEMBER_VERSION);
- if (versionMapping != null)
- {
- // Surrogate version column returned by query
- JavaTypeMapping mapping = versionMapping.getMapping();
- Object version = mapping.getObject(om, rs, versionMapping.getColumnPositions());
- StateManager objSM = om.findStateManager(obj);
- objSM.setVersion(version);
- }
- }
-
- return obj;
- }
-
- /**
- * Convenience method to return if the current row implies a null persistent object identity.
- * This can happen if the result set has a LEFT OUTER JOIN relating to a null object.
- * @param cls The class
- * @param rs ResultSet
- * @param om ObjectManager
- * @return Whether it is null
- */
- private boolean identityIsNull(Class cls, ResultSet rs, ObjectManager om)
- {
- AbstractClassMetaData cmd = om.getMetaDataManager().getMetaDataForClass(cls, om.getClassLoaderResolver());
- if (cmd.getIdentityType() == IdentityType.APPLICATION)
- {
- // Check if the PK field(s) are all null (implies null object, when using OUTER JOIN)
- int[] pkNumbers = cmd.getPKMemberPositions();
- boolean nullObject = true;
- for (int i=0;i<pkNumbers.length;i++)
- {
- StatementMappingIndex pkIdx = classMappingDef.getMappingForMemberPosition(pkNumbers[i]);
- if (pkIdx == null)
- {
- throw new NucleusException("You have just executed an SQL statement yet the information for the primary key column(s) is not available! Please generate a testcase and report this issue");
- }
- int[] colPositions = pkIdx.getColumnPositions();
- for (int j=0;j<colPositions.length;j++)
- {
- try
- {
- Object obj = rs.getObject(colPositions[j]);
- if (obj != null)
- {
- nullObject = false;
- break;
- }
- }
- catch (SQLException sqle)
- {
- NucleusLogger.DATASTORE_RETRIEVE.warn("Exception thrown while retrieving results ", sqle);
- }
- if (!nullObject)
- {
- break;
- }
- }
- }
- return nullObject;
- }
- else if (cmd.getIdentityType() == IdentityType.DATASTORE)
- {
- StatementMappingIndex datastoreIdMapping =
- classMappingDef.getMappingForMemberPosition(StatementClassMapping.MEMBER_DATASTORE_ID);
- JavaTypeMapping mapping = datastoreIdMapping.getMapping();
- OID oid = (OID)mapping.getObject(om, rs, datastoreIdMapping.getColumnPositions());
- return (oid == null);
- }
- return false;
- }
-
- /**
- * Returns a PC instance from a ResultSet row with an application identity.
- * @param om ObjectManager
- * @param resultSet The ResultSet
- * @param mappingDefinition The mapping info for the result class
- * @param fieldNumbers Numbers of the fields (of the class) found in the ResultSet
- * @param cmd MetaData for the class
- * @param pcClass PersistenceCapable class
- * @param requiresInheritanceCheck Whether we need to check the inheritance level of the returned object
- * @return The object with this application identity
- */
- private Object getObjectForApplicationId(final ObjectManager om, final Object resultSet,
- final StatementClassMapping mappingDefinition, final int[] fieldNumbers,
- AbstractClassMetaData cmd, Class pcClass, boolean requiresInheritanceCheck)
- {
- // Non-null object so convert into its object
- final MappedStoreManager storeMgr = (MappedStoreManager)om.getStoreManager();
- return om.findObjectUsingAID(pcClass, new FieldValues()
- {
- public void fetchFields(StateManager sm)
- {
- FieldManager fm =
- storeMgr.getFieldManagerForResultProcessing(sm, resultSet, mappingDefinition);
- sm.replaceFields(fieldNumbers, fm, false);
- }
- public void fetchNonLoadedFields(StateManager sm)
- {
- FieldManager fm =
- storeMgr.getFieldManagerForResultProcessing(sm, resultSet, mappingDefinition);
- sm.replaceNonLoadedFields(fieldNumbers, fm);
- }
- public FetchPlan getFetchPlanForLoading()
- {
- return fetchPlan;
- }
- }, ignoreCache, requiresInheritanceCheck);
- }
-
- /**
- * Returns a PC instance from a ResultSet row with a datastore identity.
- * @param om ObjectManager
- * @param resultSet The ResultSet
- * @param mappingDefinition The mapping info for the result class
- * @param fieldNumbers Numbers of the fields (of the class) found in the ResultSet
- * @param cmd MetaData for the class
- * @param oid The object id (not null)
- * @param pcClass The PersistenceCapable class (where we know the instance type required, null if not)
- * @return The Object
- */
- private Object getObjectForDatastoreId(final ObjectManager om, final Object resultSet,
- final StatementClassMapping mappingDefinition, final int[] fieldNumbers,
- AbstractClassMetaData cmd, Object oid, Class pcClass)
- {
- final MappedStoreManager storeMgr = (MappedStoreManager)om.getStoreManager();
- return om.findObject(oid, new FieldValues()
- {
- public void fetchFields(StateManager sm)
- {
- FieldManager fm = storeMgr.getFieldManagerForResultProcessing(sm, resultSet,
- mappingDefinition);
- sm.replaceFields(fieldNumbers, fm, false);
- }
- public void fetchNonLoadedFields(StateManager sm)
- {
- FieldManager fm = storeMgr.getFieldManagerForResultProcessing(sm, resultSet,
- mappingDefinition);
- sm.replaceNonLoadedFields(fieldNumbers, fm);
- }
- public FetchPlan getFetchPlanForLoading()
- {
- return fetchPlan;
- }
- }, pcClass, ignoreCache);
- }
+/**********************************************************************
+Copyright (c) 2002 Kelly Grizzle (TJDO) and others. All rights reserved.
+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.
+
+
+Contributors:
+2003 Erik Bengtson - removed subclasses operation
+2003 Andy Jefferson - comments, and update to returned class name
+2003 Erik Bengtson - added getObjectByAid
+2004 Erik Bengtson - throws an JDOObjectNotFoundException
+2004 Erik Bengtson - removed unused variable and import
+2004 Erik Bengtson - added support for ignoreCache
+2004 Andy Jefferson - coding standards
+2005 Andy Jefferson - added support for using discriminator to distinguish objects
+ ...
+**********************************************************************/
+package org.datanucleus.store.rdbms.query;
+
+import java.lang.reflect.Modifier;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.datanucleus.ClassLoaderResolver;
+import org.datanucleus.FetchPlan;
+import org.datanucleus.ObjectManager;
+import org.datanucleus.StateManager;
+import org.datanucleus.exceptions.NucleusException;
+import org.datanucleus.exceptions.NucleusUserException;
+import org.datanucleus.identity.OID;
+import org.datanucleus.identity.OIDFactory;
+import org.datanucleus.metadata.AbstractClassMetaData;
+import org.datanucleus.metadata.AbstractMemberMetaData;
+import org.datanucleus.metadata.DiscriminatorMetaData;
+import org.datanucleus.metadata.IdentityType;
+import org.datanucleus.metadata.InterfaceMetaData;
+import org.datanucleus.metadata.MetaDataUtils;
+import org.datanucleus.metadata.VersionMetaData;
+import org.datanucleus.store.FieldValues;
+import org.datanucleus.store.fieldmanager.FieldManager;
+import org.datanucleus.store.mapped.MappedStoreManager;
+import org.datanucleus.store.mapped.StatementClassMapping;
+import org.datanucleus.store.mapped.StatementMappingIndex;
+import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
+import org.datanucleus.store.query.ResultObjectFactory;
+import org.datanucleus.store.rdbms.RDBMSStoreManager;
+import org.datanucleus.util.NucleusLogger;
+import org.datanucleus.util.Localiser;
+import org.datanucleus.util.SoftValueMap;
+import org.datanucleus.util.StringUtils;
+
+/**
+ * ResultObjectFactory that takes a JDBC ResultSet and create a PersistenceCapable object instance for
+ * each row in the ResultSet. We use information in the result set to determine the object type; this
+ * can be a discriminator column, or can be a special "NucleusType" column defined just for result
+ * processing.
+ */
+public final class PersistentIDROF implements ResultObjectFactory
+{
+ /** Localiser for messages. */
+ protected static final Localiser LOCALISER = Localiser.getInstance(
+ "org.datanucleus.store.rdbms.Localisation", RDBMSStoreManager.class.getClassLoader());
+
+ /** Metadata for the candidate class. */
+ protected final AbstractClassMetaData acmd;
+
+ /** Persistent class that this factory will generate (may be the base class). */
+ private Class persistentClass;
+
+ /** Mapping for the statement to members of this class (and sub-objects). */
+ protected StatementClassMapping stmtMapping = null;
+
+ /** Fetch Plan to use when loading fields (if any). */
+ protected final FetchPlan fetchPlan;
+
+ /** Whether to ignore the cache */
+ private final boolean ignoreCache;
+
+ /** Resolved classes for metadata / discriminator keyed by class names. */
+ private Map resolvedClasses = new SoftValueMap();
+
+ /**
+ * Constructor.
+ * @param acmd MetaData for the class (base class)
+ * @param mappingDefinition Mapping information for the result set and how it maps to the class
+ * @param ignoreCache Whether to ignore the cache
+ * @param fetchPlan the Fetch Plan
+ * @param persistentClass Class that this factory will create instances of (or subclasses)
+ */
+ public PersistentIDROF(AbstractClassMetaData acmd, StatementClassMapping mappingDefinition,
+ boolean ignoreCache, FetchPlan fetchPlan, Class persistentClass)
+ {
+ if (mappingDefinition == null)
+ {
+ throw new NucleusException("Attempt to create PersistentIDROF with null mappingDefinition");
+ }
+
+ this.stmtMapping = mappingDefinition;
+ this.acmd = acmd;
+ this.ignoreCache = ignoreCache;
+ this.fetchPlan = fetchPlan;
+ this.persistentClass = persistentClass;
+ }
+
+ /**
+ * Method to update the persistent class that the result object factory requires.
+ * This is used where we have an Extent(BaseClass) and we pass it to a JDOQL query but the query
+ * has been specified with a candidate class that is a subclass. So we use this method to restrict
+ * the results further.
+ * @param cls The Class the result factory requires.
+ */
+ public void setPersistentClass(Class cls)
+ {
+ this.persistentClass = cls;
+ }
+
+ /**
+ * Method to convert the current ResultSet row into an Object.
+ * @param om The ObjectManager
+ * @param rs The ResultSet from the Query.
+ * @return The (persisted) object.
+ */
+ public Object getObject(final ObjectManager om, final Object rs)
+ {
+ // Find the class of the returned object in this row of the ResultSet
+ String className = null;
+ boolean requiresInheritanceCheck = true;
+ StatementMappingIndex discrimMapIdx = stmtMapping.getMappingForMemberPosition(StatementClassMapping.MEMBER_DISCRIMINATOR);
+ if (discrimMapIdx != null)
+ {
+ // Discriminator mapping registered so use that
+ try
+ {
+ String discrimValue = ((ResultSet)rs).getString(discrimMapIdx.getColumnPositions()[0]);
+ JavaTypeMapping discrimMapping = discrimMapIdx.getMapping();
+ DiscriminatorMetaData dismd =
+ (discrimMapping != null ? discrimMapping.getDatastoreContainer().getDiscriminatorMetaData() : null);
+ className = MetaDataUtils.getClassNameFromDiscriminatorValue(discrimValue, dismd, om);
+ }
+ catch (SQLException sqle)
+ {
+ NucleusLogger.DATASTORE_RETRIEVE.debug("Exception obtaining value of discriminator : " + sqle.getMessage());
+ }
+ }
+ else if (stmtMapping.getNucleusTypeColumnName() != null)
+ {
+ // Extract the object type using the NucleusType column (if available)
+ try
+ {
+ className = ((ResultSet)rs).getString(stmtMapping.getNucleusTypeColumnName()).trim();
+ }
+ catch (SQLException sqle)
+ {
+ // NucleusType column not found so ignore
+ }
+ }
+
+ ClassLoaderResolver clr = om.getClassLoaderResolver();
+ Class pcClassForObject = persistentClass;
+ if (className != null)
+ {
+ Class cls = (Class) resolvedClasses.get(className);
+ if (cls != null)
+ {
+ pcClassForObject = cls;
+ }
+ else
+ {
+ if (persistentClass.getName().equals(className))
+ {
+ pcClassForObject = persistentClass;
+ }
+ else
+ {
+ pcClassForObject = clr.classForName(className, persistentClass.getClassLoader());
+ }
+ resolvedClasses.put(className, pcClassForObject);
+ }
+ requiresInheritanceCheck = false;
+ }
+
+ if (Modifier.isAbstract(pcClassForObject.getModifiers()))
+ {
+ // Persistent class is abstract so we can't create instances of that type!
+ // This can happen if the user is using subclass-table and hasn't provided a discriminator in
+ // the table. Try going out one level and find a (single) concrete subclass
+ // TODO make this more robust and go out further
+ String[] subclasses = om.getMetaDataManager().getSubclassesForClass(pcClassForObject.getName(), false);
+ if (subclasses != null)
+ {
+ Class concreteSubclass = null;
+ int numConcreteSubclasses = 0;
+ for (int i=0;i<subclasses.length;i++)
+ {
+ Class subcls = clr.classForName(subclasses[i]);
+ if (!Modifier.isAbstract(subcls.getModifiers()))
+ {
+ numConcreteSubclasses++;
+ concreteSubclass = subcls;
+ }
+ }
+ if (numConcreteSubclasses == 1)
+ {
+ // Only one possible subclass, so use that
+ pcClassForObject = concreteSubclass;
+ NucleusLogger.PERSISTENCE.warn(LOCALISER.msg("052300",
+ pcClassForObject.getName(), concreteSubclass.getName()));
+ }
+ else if (numConcreteSubclasses == 0)
+ {
+ throw new NucleusUserException(LOCALISER.msg("052301", pcClassForObject.getName()));
+ }
+ else
+ {
+ // More than 1 possible so notify the user. Really should return the abstract
+ NucleusLogger.PERSISTENCE.warn("Found type=" + pcClassForObject +
+ " but abstract and more than 1 concrete subclass (" +
+ StringUtils.objectArrayToString(subclasses) + "). Really you need a discriminator " +
+ " to help identifying the type. Choosing " + concreteSubclass);
+ pcClassForObject = concreteSubclass; // TODO Omit this
+ requiresInheritanceCheck = true;
+ }
+ }
+ }
+
+ // Find the statement mappings and field numbers to use for the result class
+ // Caters for persistent-interfaces and the result class being an implementation
+ AbstractClassMetaData cmd = om.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
+ if (cmd == null)
+ {
+ // No way of identifying the object type so assumed to be null
+ // This can happen when selecting a class and also a related class via LEFT OUTER JOIN
+ // and the LEFT OUTER JOIN results in no related object, hence null discriminator etc
+ // TODO Improve this and check PK cols
+ return null;
+ }
+
+ int[] fieldNumbers = stmtMapping.getMemberNumbers();
+ StatementClassMapping mappingDefinition;
+ int[] mappedFieldNumbers;
+ if (acmd instanceof InterfaceMetaData)
+ {
+ // Persistent-interface : create new mapping definition for a result type of the implementation
+ mappingDefinition = new StatementClassMapping(null);
+ mappingDefinition.setNucleusTypeColumnName(stmtMapping.getNucleusTypeColumnName());
+ mappedFieldNumbers = new int[fieldNumbers.length];
+ for (int i = 0; i < fieldNumbers.length; i++)
+ {
+ AbstractMemberMetaData mmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
+ mappedFieldNumbers[i] = cmd.getAbsolutePositionOfMember(mmd.getName());
+ mappingDefinition.addMappingForMember(mappedFieldNumbers[i],
+ stmtMapping.getMappingForMemberPosition(fieldNumbers[i]));
+ }
+ }
+ else
+ {
+ // Persistent class
+ mappingDefinition = stmtMapping;
+ mappedFieldNumbers = fieldNumbers;
+ }
+
+ // Extract the object from the ResultSet
+ Object obj = null;
+ if (cmd.getIdentityType() == IdentityType.APPLICATION)
+ {
+ obj = getObjectForApplicationId(om, rs, mappingDefinition, mappedFieldNumbers,
+ cmd, pcClassForObject, requiresInheritanceCheck);
+ }
+ else if (cmd.getIdentityType() == IdentityType.DATASTORE)
+ {
+ // Generate the "oid" for this object (of type pcClassForObject), and find the object for that
+ StatementMappingIndex datastoreIdMapping =
+ stmtMapping.getMappingForMemberPosition(StatementClassMapping.MEMBER_DATASTORE_ID);
+ JavaTypeMapping mapping = datastoreIdMapping.getMapping();
+ OID oid = (OID)mapping.getObject(om, rs, datastoreIdMapping.getColumnPositions());
+ if (oid != null)
+ {
+ Object id = oid;
+ if (!pcClassForObject.getName().equals(oid.getPcClass()))
+ {
+ // Get an OID for the right inheritance level
+ id = OIDFactory.getInstance(om, pcClassForObject.getName(), oid.getKeyValue());
+ }
+
+ if (mappedFieldNumbers == null)
+ {
+ obj = om.findObject(id, false, requiresInheritanceCheck, null);
+ }
+ else
+ {
+ obj = getObjectForDatastoreId(om, rs, mappingDefinition, mappedFieldNumbers,
+ cmd, id, requiresInheritanceCheck ? null : pcClassForObject);
+ }
+ }
+ }
+ else if (cmd.getIdentityType() == IdentityType.NONDURABLE)
+ {
+ Object id = om.newObjectId(className, null);
+ if (mappedFieldNumbers == null)
+ {
+ obj = om.findObject(id, false, requiresInheritanceCheck, null);
+ }
+ else
+ {
+ obj = getObjectForDatastoreId(om, rs, mappingDefinition, mappedFieldNumbers,
+ cmd, id, pcClassForObject);
+ }
+ }
+
+ if (obj != null)
+ {
+ // Set the version of the object where possible
+ int versionFieldNumber = -1;
+ VersionMetaData vermd = cmd.getVersionMetaData();
+ if (vermd != null && vermd.getFieldName() != null)
+ {
+ // Version stored in a normal field
+ versionFieldNumber = acmd.getMetaDataForMember(vermd.getFieldName()).getAbsoluteFieldNumber();
+ if (stmtMapping.getMappingForMemberPosition(versionFieldNumber) != null)
+ {
+ StateManager objSM = om.findStateManager(obj);
+ Object verFieldValue = objSM.provideField(versionFieldNumber);
+ if (verFieldValue != null)
+ {
+ objSM.setVersion(verFieldValue);
+ }
+ }
+ }
+
+ StatementMappingIndex versionMapping =
+ stmtMapping.getMappingForMemberPosition(StatementClassMapping.MEMBER_VERSION);
+ if (versionMapping != null)
+ {
+ // Surrogate version column returned by query
+ JavaTypeMapping mapping = versionMapping.getMapping();
+ Object version = mapping.getObject(om, rs, versionMapping.getColumnPositions());
+ StateManager objSM = om.findStateManager(obj);
+ objSM.setVersion(version);
+ }
+ }
+
+ return obj;
+ }
+
+ /**
+ * Returns a PC instance from a ResultSet row with an application identity.
+ * @param om ObjectManager
+ * @param resultSet The ResultSet
+ * @param mappingDefinition The mapping info for the result class
+ * @param fieldNumbers Numbers of the fields (of the class) found in the ResultSet
+ * @param cmd MetaData for the class
+ * @param pcClass PersistenceCapable class
+ * @param requiresInheritanceCheck Whether we need to check the inheritance level of the returned object
+ * @return The object with this application identity
+ */
+ private Object getObjectForApplicationId(final ObjectManager om, final Object resultSet,
+ final StatementClassMapping mappingDefinition, final int[] fieldNumbers,
+ AbstractClassMetaData cmd, Class pcClass, boolean requiresInheritanceCheck)
+ {
+ // Check if the PK field(s) are all null (implies null object, when using OUTER JOIN)
+ int[] pkNumbers = cmd.getPKMemberPositions();
+ ResultSet rs = (ResultSet)resultSet;
+ boolean nullObject = true;
+ for (int i=0;i<pkNumbers.length;i++)
+ {
+ StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNumbers[i]);
+ if (pkIdx == null)
+ {
+ throw new NucleusException("You have just executed an SQL statement yet the information for the primary key column(s) is not available! Please generate a testcase and report this issue");
+ }
+ int[] colPositions = pkIdx.getColumnPositions();
+ for (int j=0;j<colPositions.length;j++)
+ {
+ try
+ {
+ Object obj = rs.getObject(colPositions[j]);
+ if (obj != null)
+ {
+ nullObject = false;
+ break;
+ }
+ }
+ catch (SQLException sqle)
+ {
+ NucleusLogger.DATASTORE_RETRIEVE.warn("Exception thrown while retrieving results ", sqle);
+ }
+ if (!nullObject)
+ {
+ break;
+ }
+ }
+ }
+ if (nullObject)
+ {
+ // PK column(s) are all null so is null object
+ return null;
+ }
+
+ // Non-null object so convert into its object
+ final MappedStoreManager storeMgr = (MappedStoreManager)om.getStoreManager();
+ return om.findObjectUsingAID(pcClass, new FieldValues()
+ {
+ public void fetchFields(StateManager sm)
+ {
+ FieldManager fm =
+ storeMgr.getFieldManagerForResultProcessing(sm, resultSet, mappingDefinition);
+ sm.replaceFields(fieldNumbers, fm, false);
+ }
+ public void fetchNonLoadedFields(StateManager sm)
+ {
+ FieldManager fm =
+ storeMgr.getFieldManagerForResultProcessing(sm, resultSet, mappingDefinition);
+ sm.replaceNonLoadedFields(fieldNumbers, fm);
+ }
+ public FetchPlan getFetchPlanForLoading()
+ {
+ return fetchPlan;
+ }
+ }, ignoreCache, requiresInheritanceCheck);
+ }
+
+ /**
+ * Returns a PC instance from a ResultSet row with a datastore identity.
+ * @param om ObjectManager
+ * @param resultSet The ResultSet
+ * @param mappingDefinition The mapping info for the result class
+ * @param fieldNumbers Numbers of the fields (of the class) found in the ResultSet
+ * @param cmd MetaData for the class
+ * @param oid The object id
+ * @param pcClass The PersistenceCapable class (where we know the instance type required, null if not)
+ * @return The Object
+ */
+ private Object getObjectForDatastoreId(final ObjectManager om, final Object resultSet,
+ final StatementClassMapping mappingDefinition, final int[] fieldNumbers,
+ AbstractClassMetaData cmd, Object oid, Class pcClass)
+ {
+ if (oid == null)
+ {
+ return null;
+ }
+
+ final MappedStoreManager storeMgr = (MappedStoreManager)om.getStoreManager();
+ return om.findObject(oid, new FieldValues()
+ {
+ public void fetchFields(StateManager sm)
+ {
+ FieldManager fm = storeMgr.getFieldManagerForResultProcessing(sm, resultSet,
+ mappingDefinition);
+ sm.replaceFields(fieldNumbers, fm, false);
+ }
+ public void fetchNonLoadedFields(StateManager sm)
+ {
+ FieldManager fm = storeMgr.getFieldManagerForResultProcessing(sm, resultSet,
+ mappingDefinition);
+ sm.replaceNonLoadedFields(fieldNumbers, fm);
+ }
+ public FetchPlan getFetchPlanForLoading()
+ {
+ return fetchPlan;
+ }
+ }, pcClass, ignoreCache);
+ }
}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|