Search in sources :

Example 36 with ApiAdapter

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

the class JDOHelperGetVersionMethod method getExpression.

/* (non-Javadoc)
     * @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
     */
public SQLExpression getExpression(SQLStatement stmt, SQLExpression ignore, List<SQLExpression> args) {
    if (args == null || args.size() == 0) {
        throw new NucleusUserException("Cannot invoke JDOHelper.getVersion without an argument");
    }
    SQLExpression expr = args.get(0);
    if (expr == null) {
        throw new NucleusUserException("Cannot invoke JDOHelper.getVersion on null expression");
    }
    if (expr instanceof SQLLiteral) {
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        ApiAdapter api = storeMgr.getApiAdapter();
        Object obj = ((SQLLiteral) expr).getValue();
        if (obj == null || !api.isPersistable(obj)) {
            return new NullLiteral(stmt, null, null, null);
        }
        Object ver = stmt.getRDBMSManager().getApiAdapter().getVersionForObject(obj);
        JavaTypeMapping m = stmt.getSQLExpressionFactory().getMappingForType(ver.getClass(), true);
        return new ObjectLiteral(stmt, m, ver, null);
    } else if (ObjectExpression.class.isAssignableFrom(expr.getClass())) {
        if (((ObjectExpression) expr).getJavaTypeMapping() instanceof PersistableMapping) {
            JavaTypeMapping mapping = ((ObjectExpression) expr).getJavaTypeMapping();
            DatastoreClass table = (DatastoreClass) expr.getSQLTable().getTable();
            if (// Version of candidate
            table.getIdMapping() == mapping) {
                mapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, true);
                if (mapping == null) {
                    throw new NucleusUserException("Cannot use JDOHelper.getVersion on object that has no version information");
                }
                if (table.getVersionMetaData().getVersionStrategy() == VersionStrategy.VERSION_NUMBER) {
                    return new NumericExpression(stmt, expr.getSQLTable(), mapping);
                }
                return new TemporalExpression(stmt, expr.getSQLTable(), mapping);
            }
            throw new NucleusUserException("Dont currently support JDOHelper.getVersion(ObjectExpression) for expr=" + expr + " on table=" + expr.getSQLTable());
        // TODO Implement this
        }
        return expr;
    }
    throw new IllegalExpressionOperationException("JDOHelper.getVersion", expr);
}
Also used : TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) ApiAdapter(org.datanucleus.api.ApiAdapter) ObjectLiteral(org.datanucleus.store.rdbms.sql.expression.ObjectLiteral) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) IllegalExpressionOperationException(org.datanucleus.store.rdbms.sql.expression.IllegalExpressionOperationException) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) ObjectExpression(org.datanucleus.store.rdbms.sql.expression.ObjectExpression)

Example 37 with ApiAdapter

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

the class RelationshipManagerImpl method checkOneToManyBidirectionalRelation.

/**
 * Method to check the consistency of the passed field as 1-N.
 * @param mmd MetaData for the field
 * @param clr ClassLoader resolver
 * @param ec ExecutionContext
 * @param changes List of changes to the collection
 */
protected void checkOneToManyBidirectionalRelation(AbstractMemberMetaData mmd, ClassLoaderResolver clr, ExecutionContext ec, List<RelationChange> changes) {
    for (RelationChange change : changes) {
        if (change.type == ChangeType.ADD_OBJECT) {
            if (ec.getApiAdapter().isDeleted(change.value)) {
                // The element was added but was then the element object was deleted!
                throw new NucleusUserException(Localiser.msg("013008", StringUtils.toJVMIDString(pc), mmd.getName(), StringUtils.toJVMIDString(change.value)));
            }
            AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(clr)[0];
            ObjectProvider newElementOP = ec.findObjectProvider(change.value);
            if (newElementOP != null) {
                if (newElementOP.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
                    RelationshipManager newElementRelMgr = ec.getRelationshipManager(newElementOP);
                    if (newElementRelMgr != null && newElementRelMgr.managesField(relatedMmd.getAbsoluteFieldNumber())) {
                        // Element has had the owner set, so make sure it is set to this object
                        Object newValueFieldValue = newElementOP.provideField(relatedMmd.getAbsoluteFieldNumber());
                        if (newValueFieldValue != pc && newValueFieldValue != null) {
                            ApiAdapter api = ec.getApiAdapter();
                            Object id1 = api.getIdForObject(pc);
                            Object id2 = api.getIdForObject(newValueFieldValue);
                            if (id1 != null && id2 != null && id1.equals(id2)) {
                            // Do nothing, just the difference between attached and detached form of the same object
                            // Note could add check on ExecutionContext of the two objects to be safe (detached will likely be null)
                            } else {
                                // will catch cases where the user has added it to two collections
                                throw new NucleusUserException(Localiser.msg("013009", StringUtils.toJVMIDString(pc), mmd.getName(), StringUtils.toJVMIDString(change.value), StringUtils.toJVMIDString(newValueFieldValue)));
                            }
                        }
                    }
                }
            }
        } else if (change.type == ChangeType.REMOVE_OBJECT) {
            if (ec.getApiAdapter().isDeleted(change.value)) {
            // The element was removed and was then the element object was deleted so do nothing
            } else {
                AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(clr)[0];
                ObjectProvider newElementOP = ec.findObjectProvider(change.value);
                if (newElementOP != null) {
                    if (newElementOP.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
                        RelationshipManager newElementRelMgr = ec.getRelationshipManager(newElementOP);
                        if (newElementRelMgr != null && newElementRelMgr.managesField(relatedMmd.getAbsoluteFieldNumber())) {
                            // Element has had the owner set, so make sure it is not set to this object
                            Object newValueFieldValue = newElementOP.provideField(relatedMmd.getAbsoluteFieldNumber());
                            if (newValueFieldValue == pc) {
                                // The element was removed from the collection, but was updated to have its owner set to the collection owner!
                                throw new NucleusUserException(Localiser.msg("013010", StringUtils.toJVMIDString(pc), mmd.getName(), StringUtils.toJVMIDString(change.value)));
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 38 with ApiAdapter

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

the class StateManagerImpl method detach.

/**
 * Method to detach this object.
 * If the object is detachable then it will be migrated to DETACHED state, otherwise will migrate to TRANSIENT. Used by "DetachAllOnCommit"/"DetachAllOnRollback"
 * @param state State for the detachment process
 */
public void detach(FetchPlanState state) {
    if (myEC == null) {
        return;
    }
    ApiAdapter api = myEC.getApiAdapter();
    if (myLC.isDeleted() || api.isDetached(myPC) || isDetaching()) {
        // Already deleted, detached or being detached
        return;
    }
    // Check if detachable ... if so then we detach a copy, otherwise we return a transient copy
    boolean detachable = api.isDetachable(myPC);
    if (detachable) {
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("010009", StringUtils.toJVMIDString(myPC), "" + state.getCurrentFetchDepth()));
        }
        // Call any "pre-detach" listeners
        getCallbackHandler().preDetach(myPC);
    }
    try {
        setDetaching(true);
        String detachedState = myEC.getNucleusContext().getConfiguration().getStringProperty(PropertyNames.PROPERTY_DETACH_DETACHED_STATE);
        if (detachedState.equalsIgnoreCase("all")) {
            loadUnloadedFields();
        } else if (detachedState.equalsIgnoreCase("loaded")) {
        // Do nothing since just using currently loaded fields
        } else {
            // Using fetch-groups, so honour detachmentOptions for loading/unloading
            if ((myEC.getFetchPlan().getDetachmentOptions() & FetchPlan.DETACH_LOAD_FIELDS) != 0) {
                // Load any unloaded fetch-plan fields
                loadUnloadedFieldsInFetchPlan();
            }
            if ((myEC.getFetchPlan().getDetachmentOptions() & FetchPlan.DETACH_UNLOAD_FIELDS) != 0) {
                // Unload any loaded fetch-plan fields that aren't in the current fetch plan
                unloadNonFetchPlanFields();
                // Remove the values from the detached object - not required by the spec
                int[] unloadedFields = ClassUtils.getFlagsSetTo(loadedFields, cmd.getAllMemberPositions(), false);
                if (unloadedFields != null && unloadedFields.length > 0) {
                    Persistable dummyPC = myPC.dnNewInstance(this);
                    myPC.dnCopyFields(dummyPC, unloadedFields);
                    replaceStateManager(dummyPC, null);
                }
            }
        }
        // Detach all (loaded) fields in the FetchPlan
        FieldManager detachFieldManager = new DetachFieldManager(this, cmd.getSCOMutableMemberFlags(), myFP, state, false);
        for (int i = 0; i < loadedFields.length; i++) {
            if (loadedFields[i]) {
                try {
                    // Just fetch the field since we are usually called in postCommit() so dont want to update it
                    detachFieldManager.fetchObjectField(i);
                } catch (EndOfFetchPlanGraphException eofpge) {
                    Object value = provideField(i);
                    if (api.isPersistable(value)) {
                        // PC field beyond end of graph
                        ObjectProvider valueOP = myEC.findObjectProvider(value);
                        if (!api.isDetached(value) && !(valueOP != null && valueOP.isDetaching())) {
                            // Field value is not detached or being detached so unload it
                            String fieldName = cmd.getMetaDataForManagedMemberAtAbsolutePosition(i).getName();
                            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                                NucleusLogger.PERSISTENCE.debug(Localiser.msg("026032", StringUtils.toJVMIDString(myPC), IdentityUtils.getPersistableIdentityForId(myID), fieldName));
                            }
                            unloadField(fieldName);
                        }
                    }
                // TODO What if we have collection/map that includes some objects that are not detached?
                // Currently we just leave as persistent etc but should we????
                // The problem is that with 1-N bidir fields we could unload the field incorrectly
                }
            }
        }
        if (detachable) {
            // Migrate the lifecycle state to DETACHED_CLEAN
            myLC = myLC.transitionDetach(this);
            // Update the object with its detached state
            myPC.dnReplaceFlags();
            ((Detachable) myPC).dnReplaceDetachedState();
            // Call any "post-detach" listeners
            // there is no copy, so give the same object
            getCallbackHandler().postDetach(myPC, myPC);
            Persistable toCheckPC = myPC;
            Object toCheckID = myID;
            disconnect();
            if (!toCheckPC.dnIsDetached()) {
                // Sanity check on the objects detached state
                throw new NucleusUserException(Localiser.msg("026025", toCheckPC.getClass().getName(), toCheckID));
            }
        } else {
            // Warn the user since they selected detachAllOnCommit
            NucleusLogger.PERSISTENCE.warn(Localiser.msg("026031", myPC.getClass().getName(), IdentityUtils.getPersistableIdentityForId(myID)));
            // Make the object transient
            makeTransient(null);
        }
    } finally {
        setDetaching(false);
    }
}
Also used : Detachable(org.datanucleus.enhancement.Detachable) ApiAdapter(org.datanucleus.api.ApiAdapter) Persistable(org.datanucleus.enhancement.Persistable) LoadFieldManager(org.datanucleus.store.fieldmanager.LoadFieldManager) MakeTransientFieldManager(org.datanucleus.store.fieldmanager.MakeTransientFieldManager) AttachFieldManager(org.datanucleus.store.fieldmanager.AttachFieldManager) UnsetOwnerFieldManager(org.datanucleus.store.fieldmanager.UnsetOwnerFieldManager) DetachFieldManager(org.datanucleus.store.fieldmanager.DetachFieldManager) PersistFieldManager(org.datanucleus.store.fieldmanager.PersistFieldManager) SingleValueFieldManager(org.datanucleus.store.fieldmanager.SingleValueFieldManager) DeleteFieldManager(org.datanucleus.store.fieldmanager.DeleteFieldManager) L2CachePopulateFieldManager(org.datanucleus.cache.L2CachePopulateFieldManager) FieldManager(org.datanucleus.store.fieldmanager.FieldManager) SingleTypeFieldManager(org.datanucleus.store.fieldmanager.SingleTypeFieldManager) L2CacheRetrieveFieldManager(org.datanucleus.cache.L2CacheRetrieveFieldManager) DetachFieldManager(org.datanucleus.store.fieldmanager.DetachFieldManager) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) EndOfFetchPlanGraphException(org.datanucleus.store.fieldmanager.AbstractFetchDepthFieldManager.EndOfFetchPlanGraphException)

Example 39 with ApiAdapter

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

the class StateManagerImpl method refreshFieldsInFetchPlan.

/**
 * Refreshes from the database all fields in fetch plan.
 * Called by life-cycle transitions when the object undergoes a "transitionRefresh".
 */
public void refreshFieldsInFetchPlan() {
    int[] fieldNumbers = myFP.getMemberNumbers();
    if (fieldNumbers != null && fieldNumbers.length > 0) {
        clearDirtyFlags(fieldNumbers);
        ClassUtils.clearFlags(loadedFields, fieldNumbers);
        // Can't refresh PK fields!
        markPKFieldsAsLoaded();
        boolean callPostLoad = myFP.isToCallPostLoadFetchPlan(this.loadedFields);
        // Refresh the fetch plan fields in this object
        // Make sure that the version is reset upon fetch
        setTransactionalVersion(null);
        loadFieldsFromDatastore(fieldNumbers);
        if (cmd.hasRelations(myEC.getClassLoaderResolver())) {
            // Check for cascade refreshes to related objects
            for (int i = 0; i < fieldNumbers.length; i++) {
                AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
                RelationType relationType = fmd.getRelationType(myEC.getClassLoaderResolver());
                if (relationType != RelationType.NONE && fmd.isCascadeRefresh()) {
                    // Need to refresh the related field object(s)
                    Object value = provideField(fieldNumbers[i]);
                    if (value != null) {
                        if (fmd.hasContainer()) {
                            // TODO This should replace the SCO wrapper with a new one, or reload the wrapper
                            ApiAdapter api = getExecutionContext().getApiAdapter();
                            ContainerHandler containerHandler = myEC.getTypeManager().getContainerHandler(fmd.getType());
                            for (Object object : containerHandler.getAdapter(value)) {
                                if (api.isPersistable(object)) {
                                    getExecutionContext().refreshObject(object);
                                }
                            }
                        } else if (value instanceof Persistable) {
                            // Refresh any PC fields
                            myEC.refreshObject(value);
                        }
                    }
                }
            }
        }
        updateLevel2CacheForFields(fieldNumbers);
        if (callPostLoad) {
            postLoad();
        }
        getCallbackHandler().postRefresh(myPC);
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) Persistable(org.datanucleus.enhancement.Persistable) RelationType(org.datanucleus.metadata.RelationType) ContainerHandler(org.datanucleus.store.types.ContainerHandler) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 40 with ApiAdapter

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

the class ExecutionContextImpl method attachObjectCopy.

/**
 * Method to attach a persistent detached object returning an attached copy of the object.
 * If the object is of class that is not detachable, a ClassNotDetachableException will be thrown.
 * @param ownerOP ObjectProvider of the owner object that has this in a field that causes this attach
 * @param pc The object
 * @param sco Whether it has no identity (second-class object)
 * @return The attached object
 */
public <T> T attachObjectCopy(ObjectProvider ownerOP, T pc, boolean sco) {
    assertClassPersistable(pc.getClass());
    assertDetachable(pc);
    // Store the owner for this persistable object being attached
    // For the current thread
    Map attachedOwnerByObject = getThreadContextInfo().attachedOwnerByObject;
    if (attachedOwnerByObject != null) {
        attachedOwnerByObject.put(pc, ownerOP);
    }
    ApiAdapter api = getApiAdapter();
    Object id = api.getIdForObject(pc);
    if (id != null && isInserting(pc)) {
        // Object is being inserted in this transaction
        return pc;
    } else if (id == null && !sco) {
        // Object was not persisted before so persist it
        return persistObjectInternal(pc, null, null, -1, ObjectProvider.PC);
    } else if (api.isPersistent(pc)) {
        // Already persistent hence can't be attached
        return pc;
    }
    // Object should exist in this datastore now
    T pcTarget = null;
    if (sco) {
        // SCO PC (embedded/serialised)
        boolean detached = getApiAdapter().isDetached(pc);
        ObjectProvider<T> targetOP = nucCtx.getObjectProviderFactory().newForEmbedded(this, pc, true, null, -1);
        pcTarget = targetOP.getObject();
        if (detached) {
            // If the object is detached, re-attach it
            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                NucleusLogger.PERSISTENCE.debug(Localiser.msg("010018", StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(pcTarget)));
            }
            targetOP.attachCopy(pc, sco);
        }
    } else {
        // FCO PC
        boolean detached = getApiAdapter().isDetached(pc);
        pcTarget = (T) findObject(id, false, false, pc.getClass().getName());
        if (detached) {
            T obj = null;
            // For the current thread
            Map attachedPCById = getThreadContextInfo().attachedPCById;
            if (// Only used by persistObject process
            attachedPCById != null) {
                obj = (T) attachedPCById.get(getApiAdapter().getIdForObject(pc));
            }
            if (obj != null) {
                pcTarget = obj;
            } else {
                // If the object is detached, re-attach it
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug(Localiser.msg("010018", StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(pcTarget)));
                }
                pcTarget = (T) findObjectProvider(pcTarget).attachCopy(pc, sco);
                // Save the detached-attached PCs for later reference
                if (// Only used by persistObject process
                attachedPCById != null) {
                    attachedPCById.put(getApiAdapter().getIdForObject(pc), pcTarget);
                }
            }
        }
    }
    return pcTarget;
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) ConcurrentReferenceHashMap(org.datanucleus.util.ConcurrentReferenceHashMap) Map(java.util.Map) HashMap(java.util.HashMap)

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