Search in sources :

Example 11 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-core by datanucleus.

the class IdentityUtils method getObjectFromIdString.

/**
 * Convenience method to find an object given a string form of its identity, and the metadata for the member.
 * @param idStr The id string
 * @param mmd Metadata for the member
 * @param fieldRole Role of this field (see org.datanucleus.metadata.FieldRole)
 * @param ec Execution Context
 * @param checkInheritance Whether to check the inheritance level of this object
 * @return The object
 */
public static Object getObjectFromIdString(String idStr, AbstractMemberMetaData mmd, FieldRole fieldRole, ExecutionContext ec, boolean checkInheritance) {
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    if (fieldRole == FieldRole.ROLE_FIELD && mmd.getType().isInterface()) {
        // Interface field, so use information about possible implementation types
        String[] implNames = MetaDataUtils.getInstance().getImplementationNamesForReferenceField(mmd, fieldRole, clr, ec.getMetaDataManager());
        if (implNames == null || implNames.length == 0) {
            // No known implementations so no way of knowing the type
            return null;
        }
        AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(implNames[0], clr);
        if (cmd.getIdentityType() == IdentityType.DATASTORE) {
            Object id = ec.getNucleusContext().getIdentityManager().getDatastoreId(idStr);
            return ec.findObject(id, true, checkInheritance, null);
        } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
            Object id = null;
            for (int i = 0; i < implNames.length; i++) {
                if (i != 0) {
                    cmd = ec.getMetaDataManager().getMetaDataForClass(implNames[i], clr);
                }
                if (cmd.usesSingleFieldIdentityClass()) {
                    id = ec.getNucleusContext().getIdentityManager().getApplicationId(clr, cmd, idStr);
                } else {
                    id = ec.newObjectId(clr.classForName(cmd.getFullClassName()), idStr);
                }
                try {
                    return ec.findObject(id, true, checkInheritance, null);
                } catch (NucleusObjectNotFoundException nonfe) {
                // Presumably not this implementation
                }
            }
        }
    } else // TODO Allow for collection<interface>, map<interface, ?>, map<?, interface>, interface[]
    {
        AbstractClassMetaData cmd = null;
        if (fieldRole == FieldRole.ROLE_COLLECTION_ELEMENT) {
            cmd = mmd.getCollection().getElementClassMetaData(clr);
        } else if (fieldRole == FieldRole.ROLE_ARRAY_ELEMENT) {
            cmd = mmd.getArray().getElementClassMetaData(clr);
        } else if (fieldRole == FieldRole.ROLE_MAP_KEY) {
            cmd = mmd.getMap().getKeyClassMetaData(clr);
        } else if (fieldRole == FieldRole.ROLE_MAP_KEY) {
            cmd = mmd.getMap().getKeyClassMetaData(clr);
        } else {
            cmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
        }
        Object id = null;
        if (cmd.getIdentityType() == IdentityType.DATASTORE) {
            id = ec.getNucleusContext().getIdentityManager().getDatastoreId(idStr);
        } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
            if (cmd.usesSingleFieldIdentityClass()) {
                // Single-Field identity doesn't have the class name in the string, so cater for the root being abstract
                Class cls = clr.classForName(cmd.getFullClassName());
                if (Modifier.isAbstract(cls.getModifiers())) {
                    // Try to find a non-abstract subclass candidate
                    // TODO Allow for all possibilities rather than just first non-abstract branch
                    String[] subclasses = ec.getMetaDataManager().getSubclassesForClass(cmd.getFullClassName(), false);
                    if (subclasses != null) {
                        for (int i = 0; i < subclasses.length; i++) {
                            cls = clr.classForName(subclasses[i]);
                            if (!Modifier.isAbstract(cls.getModifiers())) {
                                cmd = ec.getMetaDataManager().getMetaDataForClass(cls, clr);
                                break;
                            }
                        }
                    }
                }
                id = ec.getNucleusContext().getIdentityManager().getApplicationId(clr, cmd, idStr);
            } else {
                Class cls = clr.classForName(cmd.getFullClassName());
                id = ec.newObjectId(cls, idStr);
            }
        }
        return ec.findObject(id, true, checkInheritance, null);
    }
    return null;
}
Also used : ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Example 12 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-core by datanucleus.

the class ExecutionContextImpl method close.

/**
 * Method to close the context.
 */
public void close() {
    if (closed) {
        throw new NucleusUserException(Localiser.msg("010002"));
    }
    if (tx.getIsActive()) {
        String closeActionTxAction = nucCtx.getConfiguration().getStringProperty(PropertyNames.PROPERTY_EXECUTION_CONTEXT_CLOSE_ACTIVE_TX_ACTION);
        if (closeActionTxAction != null) {
            if (closeActionTxAction.equalsIgnoreCase("exception")) {
                throw new TransactionActiveOnCloseException(this);
            } else if (closeActionTxAction.equalsIgnoreCase("rollback")) {
                NucleusLogger.GENERAL.warn("ExecutionContext closed with active transaction, so rolling back the active transaction");
                tx.rollback();
            }
        }
    }
    // Commit any outstanding non-tx updates
    if (!dirtyOPs.isEmpty() && tx.getNontransactionalWrite()) {
        if (isNonTxAtomic()) {
            // TODO Remove this when all mutator operations handle it atomically
            // Process as nontransactional update
            processNontransactionalUpdate();
        } else {
            // Process within a transaction
            try {
                tx.begin();
                tx.commit();
            } finally {
                if (tx.isActive()) {
                    tx.rollback();
                }
            }
        }
    }
    if (properties.getFrequentProperties().getDetachOnClose() && cache != null && !cache.isEmpty()) {
        // "Detach-on-Close", detaching all currently cached objects
        // TODO This will remove objects from the L1 cache one-by-one. Is there a possibility for optimisation? See also AttachDetachTest.testDetachOnClose
        NucleusLogger.PERSISTENCE.debug(Localiser.msg("010011"));
        List<ObjectProvider> toDetach = new ArrayList<>(cache.values());
        try {
            if (!tx.getNontransactionalRead()) {
                tx.begin();
            }
            for (ObjectProvider op : toDetach) {
                if (op != null && op.getObject() != null && !op.getExecutionContext().getApiAdapter().isDeleted(op.getObject()) && op.getExternalObjectId() != null) {
                    // If the object is deleted then no point detaching. An object can be in L1 cache if transient and passed in to a query as a param for example
                    try {
                        op.detach(new DetachState(getApiAdapter()));
                    } catch (NucleusObjectNotFoundException onfe) {
                    // Catch exceptions for any objects that are deleted in other managers whilst having this open
                    }
                }
            }
            if (!tx.getNontransactionalRead()) {
                tx.commit();
            }
        } finally {
            if (!tx.getNontransactionalRead()) {
                if (tx.isActive()) {
                    tx.rollback();
                }
            }
        }
        NucleusLogger.PERSISTENCE.debug(Localiser.msg("010012"));
    }
    // Call all listeners to do their clean up TODO Why is this here and not after "disconnect remaining resources" or before "detachOnClose"?
    ExecutionContext.LifecycleListener[] listener = nucCtx.getExecutionContextListeners();
    for (int i = 0; i < listener.length; i++) {
        listener[i].preClose(this);
    }
    closing = true;
    // Disconnect remaining resources
    if (cache != null && !cache.isEmpty()) {
        // Clear out the cache (use separate list since sm.disconnect will remove the object from "cache" so we avoid any ConcurrentModification issues)
        Collection<ObjectProvider> cachedOPsClone = new HashSet<>(cache.values());
        for (ObjectProvider op : cachedOPsClone) {
            if (op != null) {
                // Remove it from any transaction
                op.disconnect();
            } else {
                NucleusLogger.CACHE.error(">> EC.close L1Cache op IS NULL!");
            }
        }
        cache.clear();
        if (NucleusLogger.CACHE.isDebugEnabled()) {
            NucleusLogger.CACHE.debug(Localiser.msg("003011"));
        }
    } else {
    // TODO If there is no cache we need a way for ObjectProviders to be disconnected; have ObjectProvider as listener for EC close? (ecListeners below)
    }
    // Clear out lifecycle listeners that were registered
    closeCallbackHandler();
    if (ecListeners != null) {
        // Inform all interested parties that we are about to close
        Set<ExecutionContextListener> listeners = new HashSet<>(ecListeners);
        for (ExecutionContextListener lstr : listeners) {
            lstr.executionContextClosing(this);
        }
        ecListeners.clear();
        ecListeners = null;
    }
    // Reset the Fetch Plan to its DFG setting
    fetchPlan.clearGroups().addGroup(FetchPlan.DEFAULT);
    if (statistics != null) {
        statistics.close();
        statistics = null;
    }
    enlistedOPCache.clear();
    dirtyOPs.clear();
    indirectDirtyOPs.clear();
    if (nontxProcessedOPs != null) {
        nontxProcessedOPs.clear();
        nontxProcessedOPs = null;
    }
    if (managedRelationsHandler != null) {
        managedRelationsHandler.clear();
    }
    if (l2CacheTxIds != null) {
        l2CacheTxIds.clear();
    }
    if (l2CacheTxFieldsToUpdateById != null) {
        l2CacheTxFieldsToUpdateById.clear();
    }
    if (pbrAtCommitHandler != null) {
        pbrAtCommitHandler.clear();
    }
    if (opEmbeddedInfoByOwner != null) {
        opEmbeddedInfoByOwner.clear();
        opEmbeddedInfoByOwner = null;
    }
    if (opEmbeddedInfoByEmbedded != null) {
        opEmbeddedInfoByEmbedded.clear();
        opEmbeddedInfoByEmbedded = null;
    }
    if (opAssociatedValuesMapByOP != null) {
        opAssociatedValuesMapByOP.clear();
        opAssociatedValuesMapByOP = null;
    }
    l2CacheObjectsToEvictUponRollback = null;
    closing = false;
    closed = true;
    // Close the transaction
    tx.close();
    tx = null;
    owner = null;
    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
        NucleusLogger.PERSISTENCE.debug(Localiser.msg("010001", this));
    }
    // Hand back to the pool for reuse
    nucCtx.getExecutionContextPool().checkIn(this);
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) TransactionActiveOnCloseException(org.datanucleus.exceptions.TransactionActiveOnCloseException) ObjectProvider(org.datanucleus.state.ObjectProvider) HashSet(java.util.HashSet)

Example 13 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-core by datanucleus.

the class ExecutionContextImpl method findObjectsById.

/**
 * Accessor for objects with the specified identities.
 * @param identities Ids of the object(s).
 * @param validate Whether to validate the object state
 * @return The Objects with these ids (same order)
 * @throws NucleusObjectNotFoundException if an object doesn't exist in the datastore
 */
public Object[] findObjectsById(Object[] identities, boolean validate) {
    if (identities == null) {
        return null;
    } else if (identities.length == 1) {
        return new Object[] { findObject(identities[0], validate, validate, null) };
    }
    for (int i = 0; i < identities.length; i++) {
        if (identities[i] == null) {
            throw new NucleusUserException(Localiser.msg("010044"));
        }
    }
    // Set the identities array
    Object[] ids = new Object[identities.length];
    for (int i = 0; i < identities.length; i++) {
        // Translate the identity if required
        if (identities[i] instanceof String) {
            IdentityStringTranslator idStringTranslator = getNucleusContext().getIdentityManager().getIdentityStringTranslator();
            if (idStringTranslator != null) {
                // DataNucleus extension to translate input identities into valid persistent identities.
                ids[i] = idStringTranslator.getIdentity(this, (String) identities[i]);
                continue;
            }
        }
        ids[i] = identities[i];
    }
    Map pcById = new HashMap(identities.length);
    List idsToFind = new ArrayList();
    ApiAdapter api = getApiAdapter();
    // Check the L1 cache
    for (int i = 0; i < ids.length; i++) {
        Object pc = getObjectFromLevel1Cache(ids[i]);
        if (pc != null) {
            if (ids[i] instanceof SCOID) {
                if (api.isPersistent(pc) && !api.isNew(pc) && !api.isDeleted(pc) && !api.isTransactional(pc)) {
                    // JDO [5.4.4] Can't return HOLLOW nondurable objects
                    throw new NucleusUserException(Localiser.msg("010005"));
                }
            }
            pcById.put(ids[i], pc);
        } else {
            idsToFind.add(ids[i]);
        }
    }
    if (!idsToFind.isEmpty() && l2CacheEnabled) {
        // Check the L2 cache for those not found
        Map pcsById = getObjectsFromLevel2Cache(idsToFind);
        if (!pcsById.isEmpty()) {
            // Found some so add to the values, and remove from the "toFind" list
            Iterator<Map.Entry> entryIter = pcsById.entrySet().iterator();
            while (entryIter.hasNext()) {
                Map.Entry entry = entryIter.next();
                pcById.put(entry.getKey(), entry.getValue());
                idsToFind.remove(entry.getKey());
            }
        }
    }
    boolean performValidationWhenCached = nucCtx.getConfiguration().getBooleanProperty(PropertyNames.PROPERTY_FIND_OBJECT_VALIDATE_WHEN_CACHED);
    List<ObjectProvider> opsToValidate = new ArrayList<>();
    if (validate) {
        if (performValidationWhenCached) {
            // Mark all ObjectProviders for validation (performed at end)
            Collection pcValues = pcById.values();
            for (Object pc : pcValues) {
                if (api.isTransactional(pc)) {
                    // This object is transactional, so no need to validate
                    continue;
                }
                // Mark this object for validation
                ObjectProvider op = findObjectProvider(pc);
                opsToValidate.add(op);
            }
        }
    }
    Object[] foundPcs = null;
    if (!idsToFind.isEmpty()) {
        // Try to find unresolved objects direct from the datastore if supported by the datastore (e.g ODBMS)
        foundPcs = getStoreManager().getPersistenceHandler().findObjects(this, idsToFind.toArray());
    }
    int foundPcIdx = 0;
    for (Object id : idsToFind) {
        // Id target class could change due to inheritance level
        Object idOrig = id;
        Object pc = foundPcs != null ? foundPcs[foundPcIdx++] : null;
        ObjectProvider op = null;
        if (pc != null) {
            // Object created by store plugin
            op = findObjectProvider(pc);
            putObjectIntoLevel1Cache(op);
        } else {
            // Object not found yet, so maybe class name is not correct inheritance level
            ClassDetailsForId details = getClassDetailsForId(id, null, validate);
            String className = details.className;
            id = details.id;
            if (details.pc != null) {
                // Found in cache from updated id
                pc = details.pc;
                op = findObjectProvider(pc);
                if (performValidationWhenCached && validate) {
                    if (!api.isTransactional(pc)) {
                        // Mark this object for validation
                        opsToValidate.add(op);
                    }
                }
            } else {
                // Still not found so create a Hollow instance with the supplied field values
                try {
                    Class pcClass = clr.classForName(className, (id instanceof DatastoreId) ? null : id.getClass().getClassLoader());
                    if (Modifier.isAbstract(pcClass.getModifiers())) {
                        // This class is abstract so impossible to have an instance of this type
                        throw new NucleusObjectNotFoundException(Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id), className));
                    }
                    op = nucCtx.getObjectProviderFactory().newForHollow(this, pcClass, id);
                    pc = op.getObject();
                    if (!validate) {
                        // Mark the ObjectProvider as needing to validate this object before loading fields
                        op.markForInheritanceValidation();
                    }
                    // Cache it in case we have bidir relations
                    putObjectIntoLevel1Cache(op);
                } catch (ClassNotResolvedException e) {
                    NucleusLogger.PERSISTENCE.warn(Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id)));
                    throw new NucleusUserException(Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id)), e);
                }
                if (validate) {
                    // Mark this object for validation
                    opsToValidate.add(op);
                }
            }
        }
        // Put in map under input id, so we find it later
        pcById.put(idOrig, pc);
    }
    if (!opsToValidate.isEmpty()) {
        // Validate the objects that need it
        try {
            getStoreManager().getPersistenceHandler().locateObjects(opsToValidate.toArray(new ObjectProvider[opsToValidate.size()]));
        } catch (NucleusObjectNotFoundException nonfe) {
            NucleusObjectNotFoundException[] nonfes = (NucleusObjectNotFoundException[]) nonfe.getNestedExceptions();
            if (nonfes != null) {
                for (int i = 0; i < nonfes.length; i++) {
                    Object missingId = nonfes[i].getFailedObject();
                    removeObjectFromLevel1Cache(missingId);
                }
            }
            throw nonfe;
        }
    }
    Object[] objs = new Object[ids.length];
    for (int i = 0; i < ids.length; i++) {
        Object id = ids[i];
        objs[i] = pcById.get(id);
    }
    return objs;
}
Also used : IdentityStringTranslator(org.datanucleus.identity.IdentityStringTranslator) Entry(java.util.Map.Entry) ApiAdapter(org.datanucleus.api.ApiAdapter) ConcurrentReferenceHashMap(org.datanucleus.util.ConcurrentReferenceHashMap) HashMap(java.util.HashMap) DatastoreId(org.datanucleus.identity.DatastoreId) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) SCOID(org.datanucleus.identity.SCOID) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) ClassNotResolvedException(org.datanucleus.exceptions.ClassNotResolvedException) Entry(java.util.Map.Entry) Collection(java.util.Collection) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) ObjectProvider(org.datanucleus.state.ObjectProvider) ConcurrentReferenceHashMap(org.datanucleus.util.ConcurrentReferenceHashMap) Map(java.util.Map) HashMap(java.util.HashMap)

Example 14 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-core by datanucleus.

the class ExecutionContextImpl method findObject.

/**
 * Accessor for an object given the object id. If validate is false, we return the object
 * if found in the cache, or otherwise a Hollow object with that id. If validate is true
 * we check with the datastore and return an object with the FetchPlan fields loaded.
 * TODO Would be nice, when using checkInheritance, to be able to specify the "id" is an instance of class X or subclass. See IdentityUtils where we have the min class
 * @param id Id of the object.
 * @param validate Whether to validate the object state
 * @param checkInheritance Whether look to the database to determine which class this object is.
 * @param objectClassName Class name for the object with this id (if known, optional)
 * @return The Object with this id
 * @throws NucleusObjectNotFoundException if the object doesn't exist in the datastore
 */
public Object findObject(Object id, boolean validate, boolean checkInheritance, String objectClassName) {
    if (id == null) {
        throw new NucleusUserException(Localiser.msg("010044"));
    }
    IdentityStringTranslator translator = getNucleusContext().getIdentityManager().getIdentityStringTranslator();
    if (translator != null && id instanceof String) {
        // DataNucleus extension to translate input identities into valid persistent identities.
        id = translator.getIdentity(this, (String) id);
    }
    ApiAdapter api = getApiAdapter();
    boolean fromCache = false;
    // try to find object in cache(s)
    Object pc = getObjectFromCache(id);
    ObjectProvider op = null;
    if (pc != null) {
        // Found in L1/L2 cache
        fromCache = true;
        if (id instanceof SCOID) {
            if (api.isPersistent(pc) && !api.isNew(pc) && !api.isDeleted(pc) && !api.isTransactional(pc)) {
                // JDO [5.4.4] Cant return HOLLOW nondurable objects
                throw new NucleusUserException(Localiser.msg("010005"));
            }
        }
        if (api.isTransactional(pc)) {
            // JDO [12.6.5] If there's already an object with the same id and it's transactional, return it
            return pc;
        }
        op = findObjectProvider(pc);
    } else {
        // Find it direct from the store if the store supports that
        pc = getStoreManager().getPersistenceHandler().findObject(this, id);
        if (pc != null) {
            op = findObjectProvider(pc);
            putObjectIntoLevel1Cache(op);
            putObjectIntoLevel2Cache(op, false);
        } else {
            // Object not found yet, so maybe class name is not correct inheritance level
            ClassDetailsForId details = getClassDetailsForId(id, objectClassName, checkInheritance);
            String className = details.className;
            id = details.id;
            if (details.pc != null) {
                // Found during inheritance check via the cache
                pc = details.pc;
                op = findObjectProvider(pc);
                fromCache = true;
            } else {
                // Still not found, so create a Hollow instance with supplied PK values if possible
                try {
                    Class pcClass = clr.classForName(className, (id instanceof DatastoreId) ? null : id.getClass().getClassLoader());
                    if (Modifier.isAbstract(pcClass.getModifiers())) {
                        // This class is abstract so impossible to have an instance of this type
                        throw new NucleusObjectNotFoundException(Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id), className));
                    }
                    op = nucCtx.getObjectProviderFactory().newForHollow(this, pcClass, id);
                    pc = op.getObject();
                    if (!checkInheritance && !validate) {
                        // Mark the ObjectProvider as needing to validate this object before loading fields
                        op.markForInheritanceValidation();
                    }
                    // Cache the object in case we have bidirectional relations that would need to find this
                    putObjectIntoLevel1Cache(op);
                } catch (ClassNotResolvedException e) {
                    NucleusLogger.PERSISTENCE.warn(Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id)));
                    throw new NucleusUserException(Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id)), e);
                }
            }
        }
    }
    boolean performValidationWhenCached = nucCtx.getConfiguration().getBooleanProperty(PropertyNames.PROPERTY_FIND_OBJECT_VALIDATE_WHEN_CACHED);
    if (validate && (!fromCache || performValidationWhenCached)) {
        // loading any fetchplan fields that are needed in the process.
        if (!fromCache) {
            // Cache the object in case we have bidirectional relations that would need to find this
            putObjectIntoLevel1Cache(op);
        }
        try {
            op.validate();
            if (op.getObject() != pc) {
                // Underlying object was changed in the validation process. This can happen when the datastore
                // is responsible for managing object references and it no longer recognises the cached value.
                fromCache = false;
                pc = op.getObject();
                putObjectIntoLevel1Cache(op);
            }
        } catch (NucleusObjectNotFoundException onfe) {
            // Object doesn't exist, so remove from L1 cache
            removeObjectFromLevel1Cache(op.getInternalObjectId());
            throw onfe;
        }
    }
    if (!fromCache) {
        // Cache the object (update it if already present)
        putObjectIntoLevel2Cache(op, false);
    }
    return pc;
}
Also used : IdentityStringTranslator(org.datanucleus.identity.IdentityStringTranslator) ApiAdapter(org.datanucleus.api.ApiAdapter) DatastoreId(org.datanucleus.identity.DatastoreId) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) SCOID(org.datanucleus.identity.SCOID) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) ClassNotResolvedException(org.datanucleus.exceptions.ClassNotResolvedException) ObjectProvider(org.datanucleus.state.ObjectProvider)

Example 15 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-core by datanucleus.

the class SCOUtils method validateObjectForWriting.

/**
 * Method to check if an object to be stored in a SCO container is already persistent, or is managed by a
 * different ExecutionContext. If not persistent, this call will persist it.
 * If not yet flushed to the datastore this call will flush it.
 * @param ec ExecutionContext
 * @param object The object
 * @param fieldValues Values for any fields when persisting (if the object needs persisting)
 * @return Whether the object was persisted during this call
 */
public static boolean validateObjectForWriting(ExecutionContext ec, Object object, FieldValues fieldValues) {
    boolean persisted = false;
    ApiAdapter api = ec.getApiAdapter();
    if (api.isPersistable(object)) {
        ExecutionContext objectEC = api.getExecutionContext(object);
        if (objectEC != null && ec != objectEC) {
            throw new NucleusUserException(Localiser.msg("023009", StringUtils.toJVMIDString(object)), api.getIdForObject(object));
        } else if (!api.isPersistent(object)) {
            // Not persistent, so either is detached, or needs persisting for first time
            boolean exists = false;
            if (api.isDetached(object)) {
                if (ec.getBooleanProperty(PropertyNames.PROPERTY_ATTACH_SAME_DATASTORE)) {
                    // Assume that it is detached from this datastore
                    exists = true;
                } else {
                    // Check if the (attached) object exists in this datastore
                    try {
                        Object obj = ec.findObject(api.getIdForObject(object), true, false, object.getClass().getName());
                        if (obj != null) {
                            // PM.getObjectById creates a dummy object to represent this object and
                            // automatically
                            // enlists it in the txn. Evict it to avoid issues with reachability
                            ObjectProvider objSM = ec.findObjectProvider(obj);
                            if (objSM != null) {
                                ec.evictFromTransaction(objSM);
                            }
                        }
                        exists = true;
                    } catch (NucleusObjectNotFoundException onfe) {
                        exists = false;
                    }
                }
            }
            if (!exists) {
                // Persist the object
                ec.persistObjectInternal(object, fieldValues, ObjectProvider.PC);
                persisted = true;
            }
        } else {
            // Persistent state, but is it flushed to the datastore?
            ObjectProvider objectSM = ec.findObjectProvider(object);
            if (objectSM.isWaitingToBeFlushedToDatastore()) {
                // Process any fieldValues
                if (fieldValues != null) {
                    objectSM.loadFieldValues(fieldValues);
                }
                // Now flush it
                objectSM.flush();
                // Mark as being persisted since is now in the datastore
                persisted = true;
            }
        }
    }
    return persisted;
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) ExecutionContext(org.datanucleus.ExecutionContext) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ObjectProvider(org.datanucleus.state.ObjectProvider) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException)

Aggregations

NucleusObjectNotFoundException (org.datanucleus.exceptions.NucleusObjectNotFoundException)27 ExecutionContext (org.datanucleus.ExecutionContext)15 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)14 ObjectProvider (org.datanucleus.state.ObjectProvider)12 PreparedStatement (java.sql.PreparedStatement)10 ResultSet (java.sql.ResultSet)10 SQLException (java.sql.SQLException)10 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)10 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)10 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)10 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)10 SQLController (org.datanucleus.store.rdbms.SQLController)10 ParameterSetter (org.datanucleus.store.rdbms.fieldmanager.ParameterSetter)10 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)10 ArrayList (java.util.ArrayList)9 List (java.util.List)8 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)8 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)6 ApiAdapter (org.datanucleus.api.ApiAdapter)6 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)6