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