use of org.datanucleus.store.rdbms.fieldmanager.ResultSetGetter in project datanucleus-rdbms by datanucleus.
the class MappingHelper method getObjectForApplicationIdentity.
/**
* Get the object instance for a class using application identity
* @param ec ExecutionContext
* @param mapping The mapping in which this is returned
* @param rs the ResultSet
* @param resultIndexes indexes in the result set to retrieve
* @param cmd the AbstractClassMetaData
* @return the id
*/
public static Object getObjectForApplicationIdentity(final ExecutionContext ec, JavaTypeMapping mapping, final ResultSet rs, int[] resultIndexes, AbstractClassMetaData cmd) {
ClassLoaderResolver clr = ec.getClassLoaderResolver();
// Abstract class
if (((ClassMetaData) cmd).isAbstract() && cmd.getObjectidClass() != null) {
return getObjectForAbstractClass(ec, mapping, rs, resultIndexes, cmd);
}
int totalFieldCount = cmd.getNoOfManagedMembers() + cmd.getNoOfInheritedManagedMembers();
final StatementMappingIndex[] statementExpressionIndex = new StatementMappingIndex[totalFieldCount];
int paramIndex = 0;
DatastoreClass datastoreClass = mapping.getStoreManager().getDatastoreClass(cmd.getFullClassName(), clr);
final int[] pkFieldNumbers = cmd.getPKMemberPositions();
for (int i = 0; i < pkFieldNumbers.length; ++i) {
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNumbers[i]);
JavaTypeMapping m = datastoreClass.getMemberMapping(fmd);
statementExpressionIndex[fmd.getAbsoluteFieldNumber()] = new StatementMappingIndex(m);
int[] expressionsIndex = new int[m.getNumberOfDatastoreMappings()];
for (int j = 0; j < expressionsIndex.length; j++) {
expressionsIndex[j] = resultIndexes[paramIndex++];
}
statementExpressionIndex[fmd.getAbsoluteFieldNumber()].setColumnPositions(expressionsIndex);
}
final StatementClassMapping resultMappings = new StatementClassMapping();
for (int i = 0; i < pkFieldNumbers.length; i++) {
resultMappings.addMappingForMember(pkFieldNumbers[i], statementExpressionIndex[pkFieldNumbers[i]]);
}
// TODO Use any other (non-PK) param values
final FieldManager resultsFM = new ResultSetGetter(ec, rs, resultMappings, cmd);
Object id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, cmd, null, false, resultsFM);
Class type = ec.getClassLoaderResolver().classForName(cmd.getFullClassName());
return ec.findObject(id, new FieldValues() {
public void fetchFields(ObjectProvider sm) {
sm.replaceFields(pkFieldNumbers, resultsFM);
}
public void fetchNonLoadedFields(ObjectProvider sm) {
sm.replaceNonLoadedFields(pkFieldNumbers, resultsFM);
}
public FetchPlan getFetchPlanForLoading() {
return ec.getFetchPlan();
}
}, type, false, true);
}
use of org.datanucleus.store.rdbms.fieldmanager.ResultSetGetter in project datanucleus-rdbms by datanucleus.
the class FetchRequest method execute.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.request.Request#execute(org.datanucleus.state.ObjectProvider)
*/
public void execute(ObjectProvider op) {
if (fieldsToFetch != null && NucleusLogger.PERSISTENCE.isDebugEnabled()) {
// Debug information about what we are retrieving
NucleusLogger.PERSISTENCE.debug(Localiser.msg("052218", op.getObjectAsPrintable(), fieldsToFetch, table));
}
if (((fetchingSurrogateVersion || versionFieldName != null) && numberOfFieldsToFetch == 0) && op.isVersionLoaded()) {
// Fetching only the version and it is already loaded, so do nothing
} else if (statementLocked != null) {
ExecutionContext ec = op.getExecutionContext();
RDBMSStoreManager storeMgr = table.getStoreManager();
boolean locked = ec.getSerializeReadForClass(op.getClassMetaData().getFullClassName());
LockMode lockType = ec.getLockManager().getLockMode(op.getInternalObjectId());
if (lockType != LockMode.LOCK_NONE) {
if (lockType == LockMode.LOCK_PESSIMISTIC_READ || lockType == LockMode.LOCK_PESSIMISTIC_WRITE) {
// Override with pessimistic lock
locked = true;
}
}
String statement = (locked ? statementLocked : statementUnlocked);
StatementClassMapping mappingDef = mappingDefinition;
/*if ((sm.isDeleting() || sm.isDetaching()) && mappingDefinition.hasChildMappingDefinitions())
{
// Don't fetch any children since the object is being deleted
mappingDef = mappingDefinition.cloneStatementMappingWithoutChildren();
}*/
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForQuery(mconn, statement);
AbstractClassMetaData cmd = op.getClassMetaData();
try {
// Provide the primary key field(s) to the JDBC statement
if (cmd.getIdentityType() == IdentityType.DATASTORE) {
StatementMappingIndex datastoreIdx = mappingDef.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
for (int i = 0; i < datastoreIdx.getNumberOfParameterOccurrences(); i++) {
table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, datastoreIdx.getParameterPositionsForOccurrence(i), op.getInternalObjectId());
}
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
op.provideFields(cmd.getPKMemberPositions(), new ParameterSetter(op, ps, mappingDef));
}
JavaTypeMapping multitenancyMapping = table.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false);
if (multitenancyMapping != null) {
// Provide the tenant id to the JDBC statement
StatementMappingIndex multitenancyIdx = mappingDef.getMappingForMemberPosition(SurrogateColumnType.MULTITENANCY.getFieldNumber());
String tenantId = ec.getNucleusContext().getMultiTenancyId(ec, cmd);
for (int i = 0; i < multitenancyIdx.getNumberOfParameterOccurrences(); i++) {
multitenancyMapping.setObject(ec, ps, multitenancyIdx.getParameterPositionsForOccurrence(i), tenantId);
}
}
JavaTypeMapping softDeleteMapping = table.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false);
if (softDeleteMapping != null) {
// Set SoftDelete parameter in statement
StatementMappingIndex softDeleteIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.SOFTDELETE.getFieldNumber());
for (int i = 0; i < softDeleteIdx.getNumberOfParameterOccurrences(); i++) {
softDeleteMapping.setObject(ec, ps, softDeleteIdx.getParameterPositionsForOccurrence(i), Boolean.FALSE);
}
}
// Execute the statement
ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
try {
// Check for failure to find the object
if (!rs.next()) {
if (NucleusLogger.DATASTORE_RETRIEVE.isInfoEnabled()) {
NucleusLogger.DATASTORE_RETRIEVE.info(Localiser.msg("050018", op.getInternalObjectId()));
}
throw new NucleusObjectNotFoundException("No such database row", op.getInternalObjectId());
}
// Copy the results into the object
ResultSetGetter rsGetter = new ResultSetGetter(ec, rs, mappingDef, op.getClassMetaData());
rsGetter.setObjectProvider(op);
op.replaceFields(memberNumbersToFetch, rsGetter);
if (op.getTransactionalVersion() == null) {
// Object has no version set so update it from this fetch
Object datastoreVersion = null;
if (fetchingSurrogateVersion) {
// Surrogate version column - get from the result set using the version mapping
StatementMappingIndex verIdx = mappingDef.getMappingForMemberPosition(SurrogateColumnType.VERSION.getFieldNumber());
datastoreVersion = table.getSurrogateMapping(SurrogateColumnType.VERSION, true).getObject(ec, rs, verIdx.getColumnPositions());
} else if (versionFieldName != null) {
// Version field - now populated in the field in the object from the results
datastoreVersion = op.provideField(cmd.getAbsolutePositionOfMember(versionFieldName));
}
op.setVersion(datastoreVersion);
}
} finally {
rs.close();
}
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException sqle) {
String msg = Localiser.msg("052219", op.getObjectAsPrintable(), statement, sqle.getMessage());
NucleusLogger.DATASTORE_RETRIEVE.warn(msg);
List exceptions = new ArrayList();
exceptions.add(sqle);
while ((sqle = sqle.getNextException()) != null) {
exceptions.add(sqle);
}
throw new NucleusDataStoreException(msg, (Throwable[]) exceptions.toArray(new Throwable[exceptions.size()]));
}
}
// Execute any mapping actions now that we have fetched the fields
for (int i = 0; i < callbacks.length; ++i) {
callbacks[i].postFetch(op);
}
}
use of org.datanucleus.store.rdbms.fieldmanager.ResultSetGetter in project datanucleus-rdbms by datanucleus.
the class LocateBulkRequest method processResults.
private ObjectProvider[] processResults(ResultSet rs, ObjectProvider[] ops) throws SQLException {
List<ObjectProvider> missingOps = new ArrayList<>();
for (int i = 0; i < ops.length; i++) {
missingOps.add(ops[i]);
}
ExecutionContext ec = ops[0].getExecutionContext();
while (rs.next()) {
FieldManager resultFM = new ResultSetGetter(ec, rs, resultMapping, cmd);
Object id = null;
Object key = null;
if (cmd.getIdentityType() == IdentityType.DATASTORE) {
StatementMappingIndex idx = resultMapping.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
JavaTypeMapping idMapping = idx.getMapping();
key = idMapping.getObject(ec, rs, idx.getColumnPositions());
if (IdentityUtils.isDatastoreIdentity(key)) {
// If mapping is OIDMapping then returns an OID rather than the column value
key = IdentityUtils.getTargetKeyForDatastoreIdentity(key);
}
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
if (cmd.usesSingleFieldIdentityClass()) {
int[] pkFieldNums = cmd.getPKMemberPositions();
AbstractMemberMetaData pkMmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNums[0]);
if (pkMmd.getType() == int.class) {
key = resultFM.fetchIntField(pkFieldNums[0]);
} else if (pkMmd.getType() == short.class) {
key = resultFM.fetchShortField(pkFieldNums[0]);
} else if (pkMmd.getType() == long.class) {
key = resultFM.fetchLongField(pkFieldNums[0]);
} else if (pkMmd.getType() == char.class) {
key = resultFM.fetchCharField(pkFieldNums[0]);
} else if (pkMmd.getType() == boolean.class) {
key = resultFM.fetchBooleanField(pkFieldNums[0]);
} else if (pkMmd.getType() == byte.class) {
key = resultFM.fetchByteField(pkFieldNums[0]);
} else if (pkMmd.getType() == double.class) {
key = resultFM.fetchDoubleField(pkFieldNums[0]);
} else if (pkMmd.getType() == float.class) {
key = resultFM.fetchFloatField(pkFieldNums[0]);
} else if (pkMmd.getType() == String.class) {
key = resultFM.fetchStringField(pkFieldNums[0]);
} else {
key = resultFM.fetchObjectField(pkFieldNums[0]);
}
} else {
id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, cmd, null, true, resultFM);
}
}
// Find which ObjectProvider this row is for
ObjectProvider op = null;
for (ObjectProvider missingOp : missingOps) {
Object opId = missingOp.getInternalObjectId();
if (cmd.getIdentityType() == IdentityType.DATASTORE) {
Object opKey = IdentityUtils.getTargetKeyForDatastoreIdentity(opId);
if (key != null && opKey.getClass() != key.getClass()) {
opKey = TypeConversionHelper.convertTo(opKey, key.getClass());
}
if (opKey.equals(key)) {
op = missingOp;
break;
}
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
if (cmd.usesSingleFieldIdentityClass()) {
Object opKey = IdentityUtils.getTargetKeyForSingleFieldIdentity(opId);
if (opKey.equals(key)) {
op = missingOp;
break;
}
} else {
if (opId.equals(id)) {
op = missingOp;
break;
}
}
}
}
if (op != null) {
// Mark ObjectProvider as processed
missingOps.remove(op);
// Load up any unloaded fields that we have selected
int[] selectedMemberNums = resultMapping.getMemberNumbers();
int[] unloadedMemberNums = ClassUtils.getFlagsSetTo(op.getLoadedFields(), selectedMemberNums, false);
if (unloadedMemberNums != null && unloadedMemberNums.length > 0) {
op.replaceFields(unloadedMemberNums, resultFM);
}
// Load version if present and not yet set
JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
if (op.getTransactionalVersion() == null && versionMapping != null) {
VersionMetaData currentVermd = table.getVersionMetaData();
Object datastoreVersion = null;
if (currentVermd != null) {
if (currentVermd.getFieldName() == null) {
// Surrogate version
// Why use true now?
versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, true);
StatementMappingIndex verIdx = resultMapping.getMappingForMemberPosition(SurrogateColumnType.VERSION.getFieldNumber());
datastoreVersion = versionMapping.getObject(ec, rs, verIdx.getColumnPositions());
} else {
datastoreVersion = op.provideField(cmd.getAbsolutePositionOfMember(currentVermd.getFieldName()));
}
op.setVersion(datastoreVersion);
}
}
}
}
if (!missingOps.isEmpty()) {
return missingOps.toArray(new ObjectProvider[missingOps.size()]);
}
return null;
}
use of org.datanucleus.store.rdbms.fieldmanager.ResultSetGetter in project datanucleus-rdbms by datanucleus.
the class ResultMetaDataROF method getObject.
/**
* Accessor for the object(s) from the current row of the ResultSet.
* @return The object(s) for this row of the ResultSet.
*/
public Object getObject() {
List returnObjects = new ArrayList();
// A). Process persistent types
PersistentTypeMapping[] persistentTypes = queryResultMetaData.getPersistentTypeMappings();
if (persistentTypes != null) {
if (persistentTypeResultSetGetters == null) {
persistentTypeResultSetGetters = new ResultSetGetter[persistentTypes.length];
}
int startColumnIndex = 0;
for (int i = 0; i < persistentTypes.length; i++) {
Set<String> columnsInThisType = new HashSet<>();
AbstractMemberMetaData[] mmds = new AbstractMemberMetaData[columnNames.length];
Map<String, AbstractMemberMetaData> fieldColumns = new HashMap<>();
DatastoreClass dc = ((RDBMSStoreManager) ec.getStoreManager()).getDatastoreClass(persistentTypes[i].getClassName(), ec.getClassLoaderResolver());
AbstractClassMetaData acmd = ec.getMetaDataManager().getMetaDataForClass(persistentTypes[i].getClassName(), ec.getClassLoaderResolver());
Object id = null;
// and two columns with similar names e.g "Col1" and "col1". Until that situation comes up we ignore it :-)
for (int j = startColumnIndex; j < columnNames.length; j++) {
if (columnsInThisType.contains(columnNames[j])) {
// already added this column, so must be another persistent type
startColumnIndex = j;
break;
}
boolean found = false;
if (acmd.getIdentityType() == IdentityType.DATASTORE) {
JavaTypeMapping datastoreIdMapping = dc.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
Column df = datastoreIdMapping.getDatastoreMapping(0).getColumn();
if (df.getIdentifier().getName().equalsIgnoreCase(columnNames[j])) {
// add +1 because result sets in jdbc starts with 1
int datastoreIdentityExpressionIndex = j + 1;
id = datastoreIdMapping.getObject(ec, rs, new int[] { datastoreIdentityExpressionIndex });
found = true;
}
}
for (int k = 0; k < acmd.getNoOfManagedMembers() + acmd.getNoOfInheritedManagedMembers() && !found; k++) {
AbstractMemberMetaData apmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(k);
if (persistentTypes[i].getColumnForField(apmd.getName()) != null) {
if (persistentTypes[i].getColumnForField(apmd.getName()).equalsIgnoreCase(columnNames[j])) {
fieldColumns.put(columnNames[j], apmd);
columnsInThisType.add(columnNames[j]);
mmds[j] = apmd;
found = true;
}
} else {
JavaTypeMapping mapping = dc.getMemberMapping(apmd);
for (int l = 0; l < mapping.getDatastoreMappings().length && !found; l++) {
Column df = mapping.getDatastoreMapping(l).getColumn();
if (df.getIdentifier().getName().equalsIgnoreCase(columnNames[j])) {
fieldColumns.put(columnNames[j], apmd);
columnsInThisType.add(columnNames[j]);
mmds[j] = apmd;
found = true;
}
}
}
}
if (!columnsInThisType.contains(columnNames[j])) {
// column not found in this type, so must be another persistent type
startColumnIndex = j;
break;
}
}
// Build fields and mappings in the results
StatementMappingIndex[] stmtMappings = new StatementMappingIndex[acmd.getNoOfManagedMembers() + acmd.getNoOfInheritedManagedMembers()];
Set<AbstractMemberMetaData> resultMmds = new HashSet<>();
resultMmds.addAll(fieldColumns.values());
int[] resultFieldNumbers = new int[resultMmds.size()];
int j = 0;
for (AbstractMemberMetaData apmd : resultMmds) {
StatementMappingIndex stmtMapping = new StatementMappingIndex(dc.getMemberMapping(apmd));
resultFieldNumbers[j] = apmd.getAbsoluteFieldNumber();
List indexes = new ArrayList();
for (int k = 0; k < mmds.length; k++) {
if (mmds[k] == apmd) {
indexes.add(Integer.valueOf(k));
}
}
int[] indxs = new int[indexes.size()];
for (int k = 0; k < indxs.length; k++) {
// add +1 because result sets in JDBC starts with 1
indxs[k] = ((Integer) indexes.get(k)).intValue() + 1;
}
stmtMapping.setColumnPositions(indxs);
stmtMappings[resultFieldNumbers[j]] = stmtMapping;
j++;
}
Object obj = null;
Class type = ec.getClassLoaderResolver().classForName(persistentTypes[i].getClassName());
if (acmd.getIdentityType() == IdentityType.APPLICATION) {
if (persistentTypeResultSetGetters[i] == null) {
final StatementClassMapping resultMappings = new StatementClassMapping();
for (int k = 0; k < resultFieldNumbers.length; k++) {
resultMappings.addMappingForMember(resultFieldNumbers[k], stmtMappings[resultFieldNumbers[k]]);
}
persistentTypeResultSetGetters[i] = new ResultSetGetter(ec, rs, resultMappings, acmd);
}
ResultSetGetter rsGetter = persistentTypeResultSetGetters[i];
// TODO Make use of discriminator like in PersistentClassROF and set the pcClass in this?
id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, acmd, type, false, rsGetter);
obj = ec.findObject(id, new FieldValues() {
public void fetchFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceFields(resultFieldNumbers, rsGetter, false);
}
public void fetchNonLoadedFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceNonLoadedFields(resultFieldNumbers, rsGetter);
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
}, type, ignoreCache, false);
} else if (acmd.getIdentityType() == IdentityType.DATASTORE) {
if (persistentTypeResultSetGetters[i] == null) {
final StatementClassMapping resultMappings = new StatementClassMapping();
for (int k = 0; k < resultFieldNumbers.length; k++) {
resultMappings.addMappingForMember(resultFieldNumbers[k], stmtMappings[resultFieldNumbers[k]]);
}
persistentTypeResultSetGetters[i] = new ResultSetGetter(ec, rs, resultMappings, acmd);
}
ResultSetGetter rsGetter = persistentTypeResultSetGetters[i];
obj = ec.findObject(id, new FieldValues() {
public void fetchFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceFields(resultFieldNumbers, rsGetter, false);
}
public void fetchNonLoadedFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceNonLoadedFields(resultFieldNumbers, rsGetter);
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
}, type, ignoreCache, false);
} else {
// TODO Handle non-durable
NucleusLogger.QUERY.warn("We do not currently support non-durable objects in the results of this type of query.");
}
returnObjects.add(obj);
}
}
// B). Process simple columns
String[] columns = queryResultMetaData.getScalarColumns();
if (columns != null) {
for (int i = 0; i < columns.length; i++) {
try {
Object obj = rs.getObject(columns[i]);
returnObjects.add(obj);
} catch (SQLException sqe) {
String msg = Localiser.msg("059027", sqe.getMessage());
NucleusLogger.QUERY.error(msg);
throw new NucleusUserException(msg, sqe);
}
}
}
// C). Process constructor type mappings
ConstructorTypeMapping[] ctrTypeMappings = queryResultMetaData.getConstructorTypeMappings();
if (ctrTypeMappings != null) {
for (int i = 0; i < ctrTypeMappings.length; i++) {
String ctrClassName = ctrTypeMappings[i].getClassName();
Class ctrCls = ec.getClassLoaderResolver().classForName(ctrClassName);
List<ConstructorTypeColumn> ctrColumns = ctrTypeMappings[i].getColumnsForConstructor();
Class[] ctrArgTypes = null;
Object[] ctrArgVals = null;
if (ctrColumns != null && ctrColumns.size() > 0) {
int j = 0;
ctrArgTypes = new Class[ctrColumns.size()];
ctrArgVals = new Object[ctrColumns.size()];
Iterator<ConstructorTypeColumn> colIter = ctrColumns.iterator();
while (colIter.hasNext()) {
ConstructorTypeColumn ctrCol = colIter.next();
try {
Object colVal = rs.getObject(ctrCol.getColumnName());
ctrArgTypes[j] = colVal.getClass();
if (ctrCol.getJavaType() != null) {
// Attempt to convert to the type requested
ctrArgTypes[j] = ctrCol.getJavaType();
ctrArgVals[j] = TypeConversionHelper.convertTo(colVal, ctrArgTypes[j]);
} else {
ctrArgTypes[j] = colVal.getClass();
ctrArgVals[j] = colVal;
}
} catch (SQLException sqle) {
// TODO Handle this
}
j++;
}
}
returnObjects.add(ClassUtils.newInstance(ctrCls, ctrArgTypes, ctrArgVals));
}
}
if (returnObjects.size() == 0) {
// No objects so user must have supplied incorrect MetaData
return null;
} else if (returnObjects.size() == 1) {
// Return Object
return returnObjects.get(0);
} else {
// Return Object[]
return returnObjects.toArray(new Object[returnObjects.size()]);
}
}
use of org.datanucleus.store.rdbms.fieldmanager.ResultSetGetter in project datanucleus-rdbms by datanucleus.
the class PersistentClassROF method getObject.
/**
* Method to convert the current ResultSet row into a persistable Object.
* @return The persistable object.
*/
public T getObject() {
// Find the class of the returned object in this row of the ResultSet
String className = null;
boolean requiresInheritanceCheck = true;
StatementMappingIndex discrimMapIdx = resultMapping.getMappingForMemberPosition(SurrogateColumnType.DISCRIMINATOR.getFieldNumber());
if (discrimMapIdx != null) {
// Discriminator mapping registered so use that
try {
String discrimValue = rs.getString(discrimMapIdx.getColumnPositions()[0]);
if (discrimValue == null) {
// Discriminator has no value so return null object
NucleusLogger.DATASTORE_RETRIEVE.debug("Value of discriminator is null so assuming object is null");
return null;
}
JavaTypeMapping discrimMapping = discrimMapIdx.getMapping();
DiscriminatorMetaData dismd = (discrimMapping != null ? discrimMapping.getTable().getDiscriminatorMetaData() : null);
className = ec.getMetaDataManager().getClassNameFromDiscriminatorValue(discrimValue, dismd);
requiresInheritanceCheck = false;
} catch (SQLException sqle) {
NucleusLogger.DATASTORE_RETRIEVE.debug("Exception obtaining value of discriminator : " + sqle.getMessage());
}
} else if (resultMapping.getNucleusTypeColumnName() != null) {
// Extract the object type using the NucleusType column (if available)
try {
className = rs.getString(resultMapping.getNucleusTypeColumnName());
if (className == null) {
// Discriminator has no value so return null object
NucleusLogger.DATASTORE_RETRIEVE.debug("Value of determiner column is null so assuming object is null");
return null;
}
className = className.trim();
requiresInheritanceCheck = false;
} catch (SQLException sqle) {
// NucleusType column not found so ignore
}
}
ClassLoaderResolver clr = ec.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);
}
}
if (requiresInheritanceCheck) {
// Check if no instantiable subclasses
String[] subclasses = ec.getMetaDataManager().getSubclassesForClass(pcClassForObject.getName(), false);
if (subclasses == null || subclasses.length == 0) {
requiresInheritanceCheck = false;
}
}
String warnMsg = 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 = ec.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
NucleusLogger.DATASTORE_RETRIEVE.warn(Localiser.msg("052300", pcClassForObject.getName(), concreteSubclass.getName()));
pcClassForObject = concreteSubclass;
} 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
warnMsg = "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;
}
}
}
// 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 = ec.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
if (cmd == null) {
// TODO Improve this and check PK cols
return null;
}
int[] fieldNumbers = resultMapping.getMemberNumbers();
// TODO We need this on the first object only to generate the ResultSetGetter; can we optimise this?
StatementClassMapping mappingDefinition;
int[] mappedFieldNumbers;
if (rootCmd instanceof InterfaceMetaData) {
// Persistent-interface : create new mapping definition for a result type of the implementation
mappingDefinition = new StatementClassMapping();
mappingDefinition.setNucleusTypeColumnName(resultMapping.getNucleusTypeColumnName());
mappedFieldNumbers = new int[fieldNumbers.length];
for (int i = 0; i < fieldNumbers.length; i++) {
AbstractMemberMetaData mmd = rootCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
mappedFieldNumbers[i] = cmd.getAbsolutePositionOfMember(mmd.getName());
mappingDefinition.addMappingForMember(mappedFieldNumbers[i], resultMapping.getMappingForMemberPosition(fieldNumbers[i]));
}
} else {
// Persistent class
mappingDefinition = resultMapping;
mappedFieldNumbers = fieldNumbers;
}
if (resultSetGetter == null) {
// Use this result mapping definition for our ResultSetGetter
this.resultSetGetter = new ResultSetGetter(ec, rs, mappingDefinition, rootCmd);
}
// Extract any surrogate version
VersionMetaData vermd = cmd.getVersionMetaDataForClass();
Object surrogateVersion = null;
StatementMappingIndex versionMapping = null;
if (vermd != null) {
if (vermd.getFieldName() == null) {
versionMapping = resultMapping.getMappingForMemberPosition(SurrogateColumnType.VERSION.getFieldNumber());
} else {
AbstractMemberMetaData vermmd = cmd.getMetaDataForMember(vermd.getFieldName());
versionMapping = resultMapping.getMappingForMemberPosition(vermmd.getAbsoluteFieldNumber());
}
}
if (versionMapping != null) {
// Surrogate version column returned by query
JavaTypeMapping mapping = versionMapping.getMapping();
surrogateVersion = mapping.getObject(ec, rs, versionMapping.getColumnPositions());
}
// Extract the object from the ResultSet
T obj = null;
boolean needToSetVersion = false;
if (persistentClass.isInterface() && !cmd.isImplementationOfPersistentDefinition()) {
// Querying by interface, and not a generated implementation so use the metadata for the interface
cmd = ec.getMetaDataManager().getMetaDataForInterface(persistentClass, clr);
if (cmd == null) {
// Fallback to the value we had
cmd = ec.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
}
}
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 = 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 pkObj = rs.getObject(colPositions[j]);
if (pkObj != null) {
nullObject = false;
break;
}
} catch (SQLException sqle) {
NucleusLogger.DATASTORE_RETRIEVE.warn("Exception thrown while retrieving results ", sqle);
}
if (!nullObject) {
break;
}
}
}
if (!nullObject) {
// Retrieve the object with this application-identity
if (warnMsg != null) {
NucleusLogger.DATASTORE_RETRIEVE.warn(warnMsg);
}
Object id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, cmd, pcClassForObject, requiresInheritanceCheck, resultSetGetter);
String idClassName = IdentityUtils.getTargetClassNameForIdentity(id);
if (idClassName != null) {
// "identity" defines the class name
pcClassForObject = clr.classForName(idClassName);
}
obj = findObjectWithIdAndLoadFields(id, mappedFieldNumbers, pcClassForObject, cmd, surrogateVersion);
}
} else if (cmd.getIdentityType() == IdentityType.DATASTORE) {
// Generate the "id" for this object (of type pcClassForObject), and find the object for that
StatementMappingIndex datastoreIdMapping = resultMapping.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
JavaTypeMapping mapping = datastoreIdMapping.getMapping();
Object id = mapping.getObject(ec, rs, datastoreIdMapping.getColumnPositions());
if (id != null) {
String idClassName = IdentityUtils.getTargetClassNameForIdentity(id);
if (!pcClassForObject.getName().equals(idClassName)) {
// Get a DatastoreId for the right inheritance level
id = ec.getNucleusContext().getIdentityManager().getDatastoreId(pcClassForObject.getName(), IdentityUtils.getTargetKeyForDatastoreIdentity(id));
}
if (warnMsg != null) {
NucleusLogger.DATASTORE_RETRIEVE.warn(warnMsg);
}
if (mappedFieldNumbers == null) {
obj = (T) ec.findObject(id, false, requiresInheritanceCheck, null);
needToSetVersion = true;
} else {
obj = findObjectWithIdAndLoadFields(id, mappedFieldNumbers, requiresInheritanceCheck ? null : pcClassForObject, cmd, surrogateVersion);
}
}
} else if (cmd.getIdentityType() == IdentityType.NONDURABLE) {
String classNameForId = className;
if (className == null) {
// No discriminator info from the query, so just fallback to default type
classNameForId = cmd.getFullClassName();
}
Object id = ec.newObjectId(classNameForId, null);
if (mappedFieldNumbers == null) {
obj = (T) ec.findObject(id, false, requiresInheritanceCheck, null);
needToSetVersion = true;
} else {
obj = findObjectWithIdAndLoadFields(id, fieldNumbers, pcClassForObject, cmd, surrogateVersion);
}
}
if (obj != null && needToSetVersion) {
// Set the version of the object where possible
if (surrogateVersion != null) {
ObjectProvider objOP = ec.findObjectProvider(obj);
objOP.setVersion(surrogateVersion);
} else {
if (vermd != null && vermd.getFieldName() != null) {
// Version stored in a normal field
int versionFieldNumber = rootCmd.getMetaDataForMember(vermd.getFieldName()).getAbsoluteFieldNumber();
if (resultMapping.getMappingForMemberPosition(versionFieldNumber) != null) {
ObjectProvider objOP = ec.findObjectProvider(obj);
Object verFieldValue = objOP.provideField(versionFieldNumber);
if (verFieldValue != null) {
objOP.setVersion(verFieldValue);
}
}
}
}
}
return obj;
}
Aggregations