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