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);
}
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)));
}
}
}
}
}
}
}
}
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);
}
}
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);
}
}
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;
}
Aggregations