Search in sources :

Example 6 with ObjectProvider

use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.

the class LocateBulkRequest method execute.

/**
 * Method performing the location of the records in the datastore.
 * @param ops ObjectProviders to be located
 * @throws NucleusObjectNotFoundException with nested exceptions for each of missing objects (if any)
 */
public void execute(ObjectProvider[] ops) {
    if (ops == null || ops.length == 0) {
        return;
    }
    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
        // Debug information about what we are retrieving
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < ops.length; i++) {
            if (i > 0) {
                str.append(", ");
            }
            str.append(ops[i].getInternalObjectId());
        }
        NucleusLogger.PERSISTENCE.debug(Localiser.msg("052223", str.toString(), table));
    }
    ExecutionContext ec = ops[0].getExecutionContext();
    RDBMSStoreManager storeMgr = table.getStoreManager();
    AbstractClassMetaData cmd = ops[0].getClassMetaData();
    boolean locked = ec.getSerializeReadForClass(cmd.getFullClassName());
    LockMode lockType = ec.getLockManager().getLockMode(ops[0].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 = getStatement(table, ops, locked);
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, statement);
            try {
                // Provide the primary key field(s)
                for (int i = 0; i < ops.length; i++) {
                    if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                        StatementMappingIndex datastoreIdx = mappingDefinitions[i].getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
                        for (int j = 0; j < datastoreIdx.getNumberOfParameterOccurrences(); j++) {
                            table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, datastoreIdx.getParameterPositionsForOccurrence(j), ops[i].getInternalObjectId());
                        }
                    } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                        ops[i].provideFields(cmd.getPKMemberPositions(), new ParameterSetter(ops[i], ps, mappingDefinitions[i]));
                    }
                }
                // Execute the statement
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
                try {
                    ObjectProvider[] missingOps = processResults(rs, ops);
                    if (missingOps != null && missingOps.length > 0) {
                        NucleusObjectNotFoundException[] nfes = new NucleusObjectNotFoundException[missingOps.length];
                        for (int i = 0; i < nfes.length; i++) {
                            nfes[i] = new NucleusObjectNotFoundException("Object not found", missingOps[i].getInternalObjectId());
                        }
                        throw new NucleusObjectNotFoundException("Some objects were not found. Look at nested exceptions for details", nfes);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException sqle) {
        String msg = Localiser.msg("052220", ops[0].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()]));
    }
}
Also used : SQLException(java.sql.SQLException) ArrayList(java.util.ArrayList) PreparedStatement(java.sql.PreparedStatement) LockMode(org.datanucleus.state.LockMode) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SQLController(org.datanucleus.store.rdbms.SQLController) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ExecutionContext(org.datanucleus.ExecutionContext) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) ObjectProvider(org.datanucleus.state.ObjectProvider) ArrayList(java.util.ArrayList) List(java.util.List)

Example 7 with ObjectProvider

use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.

the class PersistableMapping method postInsert.

/**
 * Method executed just after the insert of the owning object, allowing any necessary action
 * to this field and the object stored in it.
 * @param op ObjectProvider for the owner
 */
public void postInsert(ObjectProvider op) {
    Object pc = op.provideField(mmd.getAbsoluteFieldNumber());
    TypeManager typeManager = op.getExecutionContext().getTypeManager();
    pc = mmd.isSingleCollection() ? singleCollectionValue(typeManager, pc) : pc;
    if (pc == null) {
        // Has been set to null so nothing to do
        return;
    }
    ClassLoaderResolver clr = op.getExecutionContext().getClassLoaderResolver();
    AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
    RelationType relationType = mmd.getRelationType(clr);
    if (relationType == RelationType.ONE_TO_ONE_BI) {
        ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
        if (otherOP == null) {
            return;
        }
        AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, op.getObject(), pc);
        if (relatedMmd == null) {
            // Fsck knows why
            throw new NucleusUserException("You have a field " + mmd.getFullFieldName() + " that is 1-1 bidir yet cannot find the equivalent field at the other side. Why is that?");
        }
        Object relatedValue = otherOP.provideField(relatedMmd.getAbsoluteFieldNumber());
        relatedValue = relatedMmd.isSingleCollection() ? singleCollectionValue(typeManager, relatedValue) : relatedValue;
        if (relatedValue == null) {
            // Managed Relations : Other side not set so update it in memory
            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                NucleusLogger.PERSISTENCE.debug(Localiser.msg("041018", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName()));
            }
            Object replaceValue = op.getObject();
            if (relatedMmd.isSingleCollection()) {
                ElementContainerHandler containerHandler = typeManager.getContainerHandler(relatedMmd.getType());
                replaceValue = containerHandler.newContainer(relatedMmd, op.getObject());
            }
            otherOP.replaceField(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
        } else if (relatedValue != op.getObject()) {
            // Managed Relations : Other side is inconsistent so throw exception
            throw new NucleusUserException(Localiser.msg("041020", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(relatedValue)));
        }
    } else if (relationType == RelationType.MANY_TO_ONE_BI && relatedMmds[0].hasCollection()) {
        // TODO Make sure we have this PC in the collection at the other side
        ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
        if (otherOP != null) {
            // Managed Relations : add to the collection on the other side
            Collection relatedColl = (Collection) otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
            if (relatedColl != null && !(relatedColl instanceof SCOCollection)) {
                // TODO Make sure the collection is a wrapper
                boolean contained = relatedColl.contains(op.getObject());
                if (!contained) {
                    NucleusLogger.PERSISTENCE.info(Localiser.msg("041022", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmds[0].getFullFieldName()));
                // TODO Enable this. Currently causes issues with PMImplTest, InheritanceStrategyTest, TCK "inheritance1.conf"
                /*relatedColl.add(op.getObject());*/
                }
            }
        }
    } else if (relationType == RelationType.MANY_TO_ONE_UNI) {
        ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
        if (otherOP == null) {
            // Related object is not yet persisted so persist it
            Object other = op.getExecutionContext().persistObjectInternal(pc, null, -1, ObjectProvider.PC);
            otherOP = op.getExecutionContext().findObjectProvider(other);
        }
        // Add join table entry
        PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
        store.add(op, otherOP);
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) RelationType(org.datanucleus.metadata.RelationType) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) TypeManager(org.datanucleus.store.types.TypeManager) Collection(java.util.Collection) SCOCollection(org.datanucleus.store.types.SCOCollection) SCOCollection(org.datanucleus.store.types.SCOCollection) ObjectProvider(org.datanucleus.state.ObjectProvider) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler) PersistableRelationStore(org.datanucleus.store.types.scostore.PersistableRelationStore)

Example 8 with ObjectProvider

use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.

the class PersistableMapping method setObjectAsValue.

/**
 * Method to set an object reference (FK) in the datastore.
 * @param ec The ExecutionContext
 * @param ps The Prepared Statement
 * @param param The parameter ids in the statement
 * @param value The value to put in the statement at these ids
 * @param ownerOP ObjectProvider for the owner object
 * @param ownerFieldNumber Field number of this PC object in the owner
 * @throws NotYetFlushedException Just put "null" in and throw "NotYetFlushedException", to be caught by ParameterSetter and will signal to the
 *     PC object being inserted that it needs to inform this object when it is inserted.
 */
private void setObjectAsValue(ExecutionContext ec, PreparedStatement ps, int[] param, Object value, ObjectProvider ownerOP, int ownerFieldNumber) {
    Object id;
    ApiAdapter api = ec.getApiAdapter();
    if (!api.isPersistable(value)) {
        throw new NucleusException(Localiser.msg("041016", value.getClass(), value)).setFatal();
    }
    ObjectProvider valueOP = ec.findObjectProvider(value);
    try {
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        // Check if the field is attributed in the datastore
        boolean hasDatastoreAttributedPrimaryKeyValues = hasDatastoreAttributedPrimaryKeyValues(ec.getMetaDataManager(), storeMgr, clr);
        boolean inserted = false;
        if (ownerFieldNumber >= 0) {
            // Field mapping : is this field of the related object present in the datastore?
            inserted = storeMgr.isObjectInserted(valueOP, ownerFieldNumber);
        } else if (mmd == null) {
            // Identity mapping : is the object inserted far enough to be considered of this mapping type?
            inserted = storeMgr.isObjectInserted(valueOP, type);
        }
        if (valueOP != null) {
            if (ec.getApiAdapter().isDetached(value) && valueOP.getReferencedPC() != null && ownerOP != null && mmd != null) {
                // Still detached but started attaching so replace the field with what will be the attached
                // Note that we have "fmd != null" here hence omitting any M-N relations where this is a join table
                // mapping
                ownerOP.replaceFieldMakeDirty(ownerFieldNumber, valueOP.getReferencedPC());
            }
            if (valueOP.isWaitingToBeFlushedToDatastore()) {
                try {
                    // Related object is not yet flushed to the datastore so flush it so we can set the FK
                    valueOP.flush();
                } catch (NotYetFlushedException nfe) {
                    // Could not flush it, maybe it has a relation to this object! so set as null TODO check nullability
                    if (ownerOP != null) {
                        ownerOP.updateFieldAfterInsert(value, ownerFieldNumber);
                    }
                    setObjectAsNull(ec, ps, param);
                    return;
                }
            }
        } else {
            if (ec.getApiAdapter().isDetached(value)) {
                // Field value is detached and not yet started attaching, so attach
                Object attachedValue = ec.persistObjectInternal(value, null, -1, ObjectProvider.PC);
                if (attachedValue != value && ownerOP != null) {
                    // Replace the field value if using copy-on-attach
                    ownerOP.replaceFieldMakeDirty(ownerFieldNumber, attachedValue);
                    // Work from attached value now that it is attached
                    value = attachedValue;
                }
                valueOP = ec.findObjectProvider(value);
            }
        }
        // 5) the value is the same object as we are inserting anyway and has its identity set
        if (inserted || !ec.isInserting(value) || (!hasDatastoreAttributedPrimaryKeyValues && (this.mmd != null && this.mmd.isPrimaryKey())) || (!hasDatastoreAttributedPrimaryKeyValues && ownerOP == valueOP && api.getIdForObject(value) != null)) {
            // The PC is either already inserted, or inserted down to the level we need, or not inserted at all,
            // or the field is a PK and identity not attributed by the datastore
            // Object either already exists, or is not yet being inserted.
            id = api.getIdForObject(value);
            // Check if the persistable object exists in this datastore
            boolean requiresPersisting = false;
            if (ec.getApiAdapter().isDetached(value) && ownerOP != null) {
                // Detached object so needs attaching
                if (ownerOP.isInserting()) {
                    // we can just return the value now and attach later (in InsertRequest)
                    if (!ec.getBooleanProperty(PropertyNames.PROPERTY_ATTACH_SAME_DATASTORE)) {
                        if (ec.getObjectFromCache(api.getIdForObject(value)) != null) {
                        // Object is in cache so exists for this datastore, so no point checking
                        } else {
                            try {
                                Object obj = ec.findObject(api.getIdForObject(value), true, false, value.getClass().getName());
                                if (obj != null) {
                                    // Make sure this object is not retained in cache etc
                                    ObjectProvider objOP = ec.findObjectProvider(obj);
                                    if (objOP != null) {
                                        ec.evictFromTransaction(objOP);
                                    }
                                    ec.removeObjectFromLevel1Cache(api.getIdForObject(value));
                                }
                            } catch (NucleusObjectNotFoundException onfe) {
                                // Object doesn't yet exist
                                requiresPersisting = true;
                            }
                        }
                    }
                } else {
                    requiresPersisting = true;
                }
            } else if (id == null) {
                // Transient object, so we need to persist it
                requiresPersisting = true;
            } else {
                ExecutionContext pcEC = ec.getApiAdapter().getExecutionContext(value);
                if (pcEC != null && ec != pcEC) {
                    throw new NucleusUserException(Localiser.msg("041015"), id);
                }
            }
            if (requiresPersisting) {
                // This PC object needs persisting (new or detached) to do the "set"
                if (mmd != null && !mmd.isCascadePersist() && !ec.getApiAdapter().isDetached(value)) {
                    // Related PC object not persistent, but cant do cascade-persist so throw exception
                    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                        NucleusLogger.PERSISTENCE.debug(Localiser.msg("007006", mmd.getFullFieldName()));
                    }
                    throw new ReachableObjectNotCascadedException(mmd.getFullFieldName(), value);
                }
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug(Localiser.msg("007007", mmd != null ? mmd.getFullFieldName() : null));
                }
                try {
                    Object pcNew = ec.persistObjectInternal(value, null, -1, ObjectProvider.PC);
                    if (hasDatastoreAttributedPrimaryKeyValues) {
                        ec.flushInternal(false);
                    }
                    id = api.getIdForObject(pcNew);
                    if (ec.getApiAdapter().isDetached(value) && ownerOP != null && mmd != null) {
                        // Update any detached reference to refer to the attached variant
                        ownerOP.replaceFieldMakeDirty(ownerFieldNumber, pcNew);
                        RelationType relationType = mmd.getRelationType(clr);
                        if (relationType == RelationType.MANY_TO_ONE_BI) {
                            // TODO Update the container to refer to the attached object
                            if (NucleusLogger.PERSISTENCE.isInfoEnabled()) {
                                NucleusLogger.PERSISTENCE.info("PCMapping.setObject : object " + ownerOP.getInternalObjectId() + " has field " + ownerFieldNumber + " that is 1-N bidirectional." + " Have just attached the N side so should really update the reference in the 1 side collection" + " to refer to this attached object. Not yet implemented");
                            }
                        } else if (relationType == RelationType.ONE_TO_ONE_BI) {
                            AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                            // TODO Cater for more than 1 related field
                            ObjectProvider relatedOP = ec.findObjectProvider(pcNew);
                            relatedOP.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), ownerOP.getObject());
                        }
                    }
                } catch (NotYetFlushedException e) {
                    setObjectAsNull(ec, ps, param);
                    throw new NotYetFlushedException(value);
                }
            }
            if (valueOP != null) {
                valueOP.setStoringPC();
            }
            // If the field doesn't map to any datastore fields (e.g remote FK), omit the set process
            if (getNumberOfDatastoreMappings() > 0) {
                if (IdentityUtils.isDatastoreIdentity(id)) {
                    Object idKey = IdentityUtils.getTargetKeyForDatastoreIdentity(id);
                    try {
                        // Try as a Long
                        getDatastoreMapping(0).setObject(ps, param[0], idKey);
                    } catch (Exception e) {
                        // Must be a String
                        getDatastoreMapping(0).setObject(ps, param[0], idKey.toString());
                    }
                } else {
                    boolean fieldsSet = false;
                    if (IdentityUtils.isSingleFieldIdentity(id) && javaTypeMappings.length > 1) {
                        Object key = IdentityUtils.getTargetKeyForSingleFieldIdentity(id);
                        AbstractClassMetaData keyCmd = ec.getMetaDataManager().getMetaDataForClass(key.getClass(), clr);
                        if (keyCmd != null && keyCmd.getIdentityType() == IdentityType.NONDURABLE) {
                            // Embedded ID - Make sure these are called starting at lowest first, in order
                            // We cannot just call OP.provideFields with all fields since that does last first
                            ObjectProvider keyOP = ec.findObjectProvider(key);
                            int[] fieldNums = keyCmd.getAllMemberPositions();
                            FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
                            for (int i = 0; i < fieldNums.length; i++) {
                                keyOP.provideFields(new int[] { fieldNums[i] }, fm);
                            }
                            fieldsSet = true;
                        }
                    }
                    if (!fieldsSet) {
                        // Copy PK fields from identity to the object
                        FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
                        api.copyKeyFieldsFromIdToObject(value, new AppIdObjectIdFieldConsumer(api, fm), id);
                    }
                }
            }
        } else {
            if (valueOP != null) {
                valueOP.setStoringPC();
            }
            if (getNumberOfDatastoreMappings() > 0) {
                // Object is in the process of being inserted so we cant use its id currently and we need to store
                // a foreign key to it (which we cant yet do). Just put "null" in and throw "NotYetFlushedException",
                // to be caught by ParameterSetter and will signal to the PC object being inserted that it needs
                // to inform this object when it is inserted.
                setObjectAsNull(ec, ps, param);
                throw new NotYetFlushedException(value);
            }
        }
    } finally {
        if (valueOP != null) {
            valueOP.unsetStoringPC();
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) AppIDObjectIdFieldManager(org.datanucleus.store.rdbms.mapping.AppIDObjectIdFieldManager) SingleValueFieldManager(org.datanucleus.store.fieldmanager.SingleValueFieldManager) FieldManager(org.datanucleus.store.fieldmanager.FieldManager) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException) NucleusException(org.datanucleus.exceptions.NucleusException) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException) ExecutionContext(org.datanucleus.ExecutionContext) RelationType(org.datanucleus.metadata.RelationType) AppIDObjectIdFieldManager(org.datanucleus.store.rdbms.mapping.AppIDObjectIdFieldManager) ObjectProvider(org.datanucleus.state.ObjectProvider) NucleusException(org.datanucleus.exceptions.NucleusException) AppIdObjectIdFieldConsumer(org.datanucleus.state.AppIdObjectIdFieldConsumer)

Example 9 with ObjectProvider

use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.

the class PersistableMapping method getObject.

/**
 * Returns an instance of a persistable class.
 * Processes the FK field and generates the id of the object from the result values, and hence the object itself.
 * TODO Pass in the discriminator/version columns also where available
 * @param ec execution context
 * @param rs The ResultSet
 * @param resultIndexes indexes in the ResultSet to retrieve
 * @return The persistable object
 */
public Object getObject(ExecutionContext ec, final ResultSet rs, int[] resultIndexes) {
    // Check for null FK
    if (storeMgr.getResultValueAtPosition(rs, this, resultIndexes[0]) == null) {
        // Assumption : if the first param is null, then the field is null
        return null;
    }
    if (cmd == null) {
        cmd = ec.getMetaDataManager().getMetaDataForClass(getType(), ec.getClassLoaderResolver());
    }
    // Return the object represented by this mapping
    Object pc = null;
    if (cmd.getIdentityType() == IdentityType.DATASTORE) {
        pc = MappingHelper.getObjectForDatastoreIdentity(ec, this, rs, resultIndexes, cmd);
    } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
        pc = MappingHelper.getObjectForApplicationIdentity(ec, this, rs, resultIndexes, cmd);
    } else {
        return null;
    }
    // Sanity check that we have loaded the version also
    ObjectProvider pcOP = ec.findObjectProvider(pc);
    if (pcOP != null) {
        VersionMetaData vermd = cmd.getVersionMetaDataForTable();
        if (vermd != null && vermd.getVersionStrategy() != VersionStrategy.NONE && ec.getTransaction().getOptimistic() && !pcOP.isVersionLoaded()) {
            // For some reason the version was not loaded on this object, and wanting to delete it, so load the version (+DFG) now.
            // This can happen when we have 1-1 between A and B and we loaded the B field of A via FetchRequest but didn't pull in the version since the inheritance wasn't knowable
            pcOP.loadUnloadedFieldsInFetchPlan();
        }
    }
    return pc;
}
Also used : VersionMetaData(org.datanucleus.metadata.VersionMetaData) ObjectProvider(org.datanucleus.state.ObjectProvider)

Example 10 with ObjectProvider

use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.

the class MultiPersistableMapping method setObject.

/**
 * Sets the specified positions in the PreparedStatement associated with this field, and value.
 * If the number of positions in "pos" is not the same as the number of datastore mappings then it is assumed
 * that we should only set the positions for the real implementation FK; this happens where we have a statement
 * like "... WHERE IMPL1_ID_OID = ? AND IMPL2_ID_OID IS NULL" so we need to filter on the other implementations
 * being null and only want to input parameter(s) for the real implementation of "value".
 * @param ec execution context
 * @param ps a datastore object that executes statements in the database
 * @param pos The position(s) of the PreparedStatement to populate
 * @param value the value stored in this field
 * @param ownerOP the owner ObjectProvider
 * @param ownerFieldNumber the owner absolute field number
 */
public void setObject(ExecutionContext ec, PreparedStatement ps, int[] pos, Object value, ObjectProvider ownerOP, int ownerFieldNumber) {
    boolean setValueFKOnly = false;
    if (pos != null && pos.length < getNumberOfDatastoreMappings()) {
        setValueFKOnly = true;
    }
    // Make sure that this field has a sub-mapping appropriate for the specified value
    int javaTypeMappingNumber = getMappingNumberForValue(ec, value);
    if (value != null && javaTypeMappingNumber == -1) {
        // TODO Change this to a multiple field mapping localised message
        throw new ClassCastException(Localiser.msg("041044", mmd != null ? mmd.getFullFieldName() : "", getType(), value.getClass().getName()));
    }
    if (value != null) {
        ApiAdapter api = ec.getApiAdapter();
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        // Make sure the value is persisted if it is persistable in its own right
        if (!ec.isInserting(value)) {
            // Object either already exists, or is not yet being inserted.
            Object id = api.getIdForObject(value);
            // Check if the persistable exists in this datastore
            boolean requiresPersisting = false;
            if (ec.getApiAdapter().isDetached(value) && ownerOP != null) {
                // Detached object that needs attaching (or persisting if detached from a different datastore)
                requiresPersisting = true;
            } else if (id == null) {
                // Transient object, so we need to persist it
                requiresPersisting = true;
            } else {
                ExecutionContext valueEC = api.getExecutionContext(value);
                if (valueEC != null && ec != valueEC) {
                    throw new NucleusUserException(Localiser.msg("041015"), id);
                }
            }
            if (requiresPersisting) {
                // The object is either not yet persistent or is detached and so needs attaching
                Object pcNew = ec.persistObjectInternal(value, null, -1, ObjectProvider.PC);
                ec.flushInternal(false);
                id = api.getIdForObject(pcNew);
                if (ec.getApiAdapter().isDetached(value) && ownerOP != null) {
                    // Update any detached reference to refer to the attached variant
                    ownerOP.replaceFieldMakeDirty(ownerFieldNumber, pcNew);
                    if (mmd != null) {
                        RelationType relationType = mmd.getRelationType(clr);
                        if (relationType == RelationType.ONE_TO_ONE_BI) {
                            ObjectProvider relatedSM = ec.findObjectProvider(pcNew);
                            AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                            // TODO Allow for multiple related fields
                            relatedSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), ownerOP.getObject());
                        } else if (relationType == RelationType.MANY_TO_ONE_BI) {
                            // TODO Update the container element with the attached variant
                            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                                NucleusLogger.PERSISTENCE.debug("PCMapping.setObject : object " + ownerOP.getInternalObjectId() + " has field " + ownerFieldNumber + " that is 1-N bidirectional - should really update the reference in the relation. Not yet supported");
                            }
                        }
                    }
                }
            }
            if (getNumberOfDatastoreMappings() <= 0) {
                // If the field doesn't map to any datastore fields, omit the set process
                return;
            }
        }
    }
    if (pos == null) {
        return;
    }
    ObjectProvider op = (value != null ? ec.findObjectProvider(value) : null);
    try {
        if (op != null) {
            op.setStoringPC();
        }
        int n = 0;
        NotYetFlushedException notYetFlushed = null;
        for (int i = 0; i < javaTypeMappings.length; i++) {
            // Set the PreparedStatement positions for this implementation mapping
            int[] posMapping;
            if (setValueFKOnly) {
                // Only using first "pos" value(s)
                n = 0;
            } else if (n >= pos.length) {
                // store all implementations to the same columns, so we reset the index
                n = 0;
            }
            if (javaTypeMappings[i].getReferenceMapping() != null) {
                posMapping = new int[javaTypeMappings[i].getReferenceMapping().getNumberOfDatastoreMappings()];
            } else {
                posMapping = new int[javaTypeMappings[i].getNumberOfDatastoreMappings()];
            }
            for (int j = 0; j < posMapping.length; j++) {
                posMapping[j] = pos[n++];
            }
            try {
                if (javaTypeMappingNumber == -2 || (value != null && javaTypeMappingNumber == i)) {
                    // This mapping is where the value is to be stored, or using persistent interfaces
                    javaTypeMappings[i].setObject(ec, ps, posMapping, value);
                } else if (!setValueFKOnly) {
                    // Set null for this mapping, since the value is null or is for something else
                    javaTypeMappings[i].setObject(ec, ps, posMapping, null);
                }
            } catch (NotYetFlushedException e) {
                notYetFlushed = e;
            }
        }
        if (notYetFlushed != null) {
            throw notYetFlushed;
        }
    } finally {
        if (op != null) {
            op.unsetStoringPC();
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) ExecutionContext(org.datanucleus.ExecutionContext) RelationType(org.datanucleus.metadata.RelationType) ObjectProvider(org.datanucleus.state.ObjectProvider) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

ObjectProvider (org.datanucleus.state.ObjectProvider)160 ExecutionContext (org.datanucleus.ExecutionContext)85 Iterator (java.util.Iterator)43 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)34 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)25 Map (java.util.Map)22 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)22 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)21 SQLException (java.sql.SQLException)17 Collection (java.util.Collection)16 ApiAdapter (org.datanucleus.api.ApiAdapter)16 NucleusObjectNotFoundException (org.datanucleus.exceptions.NucleusObjectNotFoundException)16 SCOCollectionIterator (org.datanucleus.store.types.SCOCollectionIterator)16 ArrayList (java.util.ArrayList)14 HashSet (java.util.HashSet)14 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)14 NucleusException (org.datanucleus.exceptions.NucleusException)13 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)13 ListIterator (java.util.ListIterator)12 SQLController (org.datanucleus.store.rdbms.SQLController)12