Search in sources :

Example 11 with ApiAdapter

use of org.datanucleus.api.ApiAdapter 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 12 with ApiAdapter

use of org.datanucleus.api.ApiAdapter in project datanucleus-core by datanucleus.

the class ExecutionContextImpl method postCommit.

/**
 * Commit any changes made to objects managed by the object manager to the database.
 */
public void postCommit() {
    if (properties.getFrequentProperties().getDetachAllOnCommit()) {
        // Detach-all-on-commit
        performDetachAllOnTxnEnd();
    }
    List failures = null;
    try {
        // Commit all enlisted ObjectProviders
        ApiAdapter api = getApiAdapter();
        ObjectProvider[] ops = enlistedOPCache.values().toArray(new ObjectProvider[enlistedOPCache.size()]);
        for (int i = 0; i < ops.length; ++i) {
            try {
                // TODO this if is due to sms that can have lc == null, why?, should not be here then
                if (ops[i] != null && ops[i].getObject() != null && (api.isPersistent(ops[i].getObject()) || api.isTransactional(ops[i].getObject()))) {
                    ops[i].postCommit(getTransaction());
                    // TODO Change this check so that we remove all objects that are no longer suitable for caching
                    if (properties.getFrequentProperties().getDetachAllOnCommit() && api.isDetachable(ops[i].getObject())) {
                        // "DetachAllOnCommit" - Remove the object from the L1 cache since it is now detached
                        removeObjectProviderFromCache(ops[i]);
                    }
                }
            } catch (RuntimeException e) {
                if (failures == null) {
                    failures = new ArrayList();
                }
                failures.add(e);
            }
        }
    } finally {
        resetTransactionalVariables();
    }
    if (failures != null && !failures.isEmpty()) {
        throw new CommitStateTransitionException((Exception[]) failures.toArray(new Exception[failures.size()]));
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) CommitStateTransitionException(org.datanucleus.exceptions.CommitStateTransitionException) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) ObjectProvider(org.datanucleus.state.ObjectProvider) ClassNotDetachableException(org.datanucleus.exceptions.ClassNotDetachableException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) RollbackStateTransitionException(org.datanucleus.exceptions.RollbackStateTransitionException) NucleusException(org.datanucleus.exceptions.NucleusException) NucleusFatalUserException(org.datanucleus.exceptions.NucleusFatalUserException) ClassNotPersistableException(org.datanucleus.exceptions.ClassNotPersistableException) NoPersistenceInformationException(org.datanucleus.exceptions.NoPersistenceInformationException) TransactionActiveOnCloseException(org.datanucleus.exceptions.TransactionActiveOnCloseException) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassNotResolvedException(org.datanucleus.exceptions.ClassNotResolvedException) NucleusOptimisticException(org.datanucleus.exceptions.NucleusOptimisticException) CommitStateTransitionException(org.datanucleus.exceptions.CommitStateTransitionException) TransactionNotActiveException(org.datanucleus.exceptions.TransactionNotActiveException) ObjectDetachedException(org.datanucleus.exceptions.ObjectDetachedException)

Example 13 with ApiAdapter

use of org.datanucleus.api.ApiAdapter 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)

Example 14 with ApiAdapter

use of org.datanucleus.api.ApiAdapter in project datanucleus-core by datanucleus.

the class SCOUtils method attachForMap.

/**
 * Convenience method to attach (recursively) all keys/values for a map field. All keys/values that are
 * persistable and don't already have an attached object will be attached.
 * @param ownerOP ObjectProvider for the owning object with the map
 * @param entries The entries in the map to process
 * @param keysWithoutIdentity Whether the keys have their own identity
 * @param valuesWithoutIdentity Whether the values have their own identity
 */
public static void attachForMap(ObjectProvider ownerOP, Set entries, boolean keysWithoutIdentity, boolean valuesWithoutIdentity) {
    ExecutionContext ec = ownerOP.getExecutionContext();
    ApiAdapter api = ec.getApiAdapter();
    for (Iterator it = entries.iterator(); it.hasNext(); ) {
        Map.Entry entry = (Map.Entry) it.next();
        Object val = entry.getValue();
        Object key = entry.getKey();
        if (api.isPersistable(key)) {
            Object attached = ec.getAttachedObjectForId(api.getIdForObject(key));
            if (attached == null) {
                // Not yet attached so attach
                ownerOP.getExecutionContext().attachObject(ownerOP, key, keysWithoutIdentity);
            }
        }
        if (api.isPersistable(val)) {
            Object attached = ec.getAttachedObjectForId(api.getIdForObject(val));
            if (attached == null) {
                // Not yet attached so attach
                ownerOP.getExecutionContext().attachObject(ownerOP, val, valuesWithoutIdentity);
            }
        }
    }
}
Also used : ExecutionContext(org.datanucleus.ExecutionContext) ApiAdapter(org.datanucleus.api.ApiAdapter) Iterator(java.util.Iterator) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 15 with ApiAdapter

use of org.datanucleus.api.ApiAdapter in project datanucleus-core by datanucleus.

the class SCOUtils method detachForMap.

/**
 * Convenience method to detach (recursively) all elements for a map field. All elements that are
 * persistable will be detached.
 * @param ownerOP ObjectProvider for the owning object with the map
 * @param entries The entries in the map
 * @param state FetchPlan state
 */
public static void detachForMap(ObjectProvider ownerOP, Set entries, FetchPlanState state) {
    ApiAdapter api = ownerOP.getExecutionContext().getApiAdapter();
    for (Iterator it = entries.iterator(); it.hasNext(); ) {
        Map.Entry entry = (Map.Entry) it.next();
        Object val = entry.getValue();
        Object key = entry.getKey();
        if (api.isPersistable(key)) {
            ownerOP.getExecutionContext().detachObject(state, key);
        }
        if (api.isPersistable(val)) {
            ownerOP.getExecutionContext().detachObject(state, val);
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) Iterator(java.util.Iterator) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Aggregations

ApiAdapter (org.datanucleus.api.ApiAdapter)53 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)19 ObjectProvider (org.datanucleus.state.ObjectProvider)16 ExecutionContext (org.datanucleus.ExecutionContext)12 Map (java.util.Map)11 NucleusException (org.datanucleus.exceptions.NucleusException)11 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)10 Iterator (java.util.Iterator)8 NucleusObjectNotFoundException (org.datanucleus.exceptions.NucleusObjectNotFoundException)8 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)8 Collection (java.util.Collection)7 HashMap (java.util.HashMap)7 RelationType (org.datanucleus.metadata.RelationType)7 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)7 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)6 ClassNotResolvedException (org.datanucleus.exceptions.ClassNotResolvedException)6 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)5 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)5 TypeManager (org.datanucleus.store.types.TypeManager)5 SortedMap (java.util.SortedMap)4