use of org.datanucleus.identity.SCOID 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.identity.SCOID 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.identity.SCOID in project datanucleus-core by datanucleus.
the class ExecutionContextImpl method findObject.
/**
* Accessor for an object given the object id and a set of field values to apply to it.
* This is intended for use where we have done a query and have the id from the results, and we want to
* create the object, preferably using the cache, and then apply any field values to it.
* @param id Id of the object.
* @param fv Field values for the object (to copy in)
* @param cls the type which the object is (optional). Used to instantiate the object
* @param ignoreCache true if it must ignore the cache
* @param checkInheritance Whether to check the inheritance on the id of the object
* @return The Object
*/
public Object findObject(Object id, FieldValues fv, Class cls, boolean ignoreCache, boolean checkInheritance) {
assertIsOpen();
Object pc = null;
ObjectProvider op = null;
if (!ignoreCache) {
// Check if an object exists in the L1/L2 caches for this id
pc = getObjectFromCache(id);
}
if (pc == null) {
// Find direct from the datastore if supported
pc = getStoreManager().getPersistenceHandler().findObject(this, id);
}
boolean createdHollow = false;
if (pc == null) {
// Determine the class details for this "id" if not provided, including checking of inheritance level
String className = cls != null ? cls.getName() : null;
if (!(id instanceof SCOID)) {
ClassDetailsForId details = getClassDetailsForId(id, className, checkInheritance);
if (details.className != null && cls != null && !cls.getName().equals(details.className)) {
cls = clr.classForName(details.className);
}
className = details.className;
id = details.id;
if (details.pc != null) {
// Found following inheritance check via the cache
pc = details.pc;
op = findObjectProvider(pc);
}
}
if (pc == null) {
// Still not found so create a Hollow instance with the supplied field values
if (cls == null) {
try {
cls = clr.classForName(className, id.getClass().getClassLoader());
} catch (ClassNotResolvedException e) {
String msg = Localiser.msg("010027", IdentityUtils.getPersistableIdentityForId(id));
NucleusLogger.PERSISTENCE.warn(msg);
throw new NucleusUserException(msg, e);
}
}
createdHollow = true;
// Will put object in L1 cache
op = nucCtx.getObjectProviderFactory().newForHollow(this, cls, id, fv);
pc = op.getObject();
putObjectIntoLevel2Cache(op, false);
}
}
if (pc != null && fv != null && !createdHollow) {
// Object found in the cache so load the requested fields
if (op == null) {
op = findObjectProvider(pc);
}
if (op != null) {
// Load the requested fields
fv.fetchNonLoadedFields(op);
}
}
return pc;
}
use of org.datanucleus.identity.SCOID in project datanucleus-core by datanucleus.
the class PersistenceNucleusContextImpl method isClassWithIdentityCacheable.
/* (non-Javadoc)
* @see org.datanucleus.NucleusContext#isClassWithIdentityCacheable(java.lang.Object)
*/
@Override
public boolean isClassWithIdentityCacheable(Object id) {
if (id == null) {
return false;
}
if (id instanceof SCOID) {
return false;
} else if (id instanceof DatastoreUniqueLongId) {
// This doesn't have the class name so can't get metadata
return false;
}
AbstractClassMetaData cmd = null;
String className = IdentityUtils.getTargetClassNameForIdentity(id);
if (className != null) {
// "Identity" defines the class name
cmd = getMetaDataManager().getMetaDataForClass(className, getClassLoaderResolver(id.getClass().getClassLoader()));
} else {
// Application identity with user PK class, so find all using this PK and take first one
Collection<AbstractClassMetaData> cmds = getMetaDataManager().getClassMetaDataWithApplicationId(id.getClass().getName());
if (cmds != null && !cmds.isEmpty()) {
cmd = cmds.iterator().next();
}
}
return isClassCacheable(cmd);
}
use of org.datanucleus.identity.SCOID in project datanucleus-rdbms by datanucleus.
the class RDBMSStoreManager method getClassNameForObjectID.
// ---------------------------------------------------------------------------------------
/**
* Returns the class corresponding to the given object identity.
* If the identity is a SCOID, return the SCO class.
* If the identity is a DatastoreId then returns the associated persistable class name.
* If the identity is a SingleFieldIdentity then returns the associated persistable class name.
* If the object is an AppID PK, returns the associated PC class (as far as determinable).
* If the object id is an application id and the user supplies the "ec" argument then a check can be performed in the datastore where necessary.
* @param id The identity of some object.
* @param clr ClassLoader resolver
* @param ec execution context (optional - to allow check inheritance level in datastore)
* @return For datastore identity, return the class of the corresponding object.
* For application identity, return the class of the corresponding object.
* Otherwise returns null if unable to tie as the identity of a particular class.
*/
public String getClassNameForObjectID(Object id, ClassLoaderResolver clr, ExecutionContext ec) {
if (id instanceof SCOID) {
// Object is a SCOID
return ((SCOID) id).getSCOClass();
}
// Generate a list of metadata for the roots of inheritance tree(s) that this identity can represent
// Really ought to be for a single inheritance tree (hence one element in the List) but we allow for
// a user reusing their PK class in multiple trees
List<AbstractClassMetaData> rootCmds = new ArrayList<>();
String className = IdentityUtils.getTargetClassNameForIdentity(id);
if (className != null) {
AbstractClassMetaData cmd = getMetaDataManager().getMetaDataForClass(className, clr);
// Basic error checking
if (IdentityUtils.isDatastoreIdentity(id) && cmd.getIdentityType() != IdentityType.DATASTORE) {
throw new NucleusUserException(Localiser.msg("038001", id, cmd.getFullClassName()));
}
if (IdentityUtils.isSingleFieldIdentity(id) && (cmd.getIdentityType() != IdentityType.APPLICATION || !cmd.getObjectidClass().equals(id.getClass().getName()))) {
throw new NucleusUserException(Localiser.msg("038001", id, cmd.getFullClassName()));
}
rootCmds.add(cmd);
} else {
// Find all of the classes with a PK class of this type
Collection<AbstractClassMetaData> pkCmds = getMetaDataManager().getClassMetaDataWithApplicationId(id.getClass().getName());
if (pkCmds != null && pkCmds.size() > 0) {
Iterator<AbstractClassMetaData> iter = pkCmds.iterator();
while (iter.hasNext()) {
AbstractClassMetaData pkCmd = iter.next();
AbstractClassMetaData cmdToSwap = null;
boolean toAdd = true;
Iterator<AbstractClassMetaData> rootCmdIterator = rootCmds.iterator();
while (rootCmdIterator.hasNext()) {
AbstractClassMetaData rootCmd = rootCmdIterator.next();
if (rootCmd.isDescendantOf(pkCmd)) {
// This cmd is a parent of an existing, so swap them
cmdToSwap = rootCmd;
toAdd = false;
break;
} else if (pkCmd.isDescendantOf(rootCmd)) {
toAdd = false;
}
}
if (cmdToSwap != null) {
rootCmds.remove(cmdToSwap);
rootCmds.add(pkCmd);
} else if (toAdd) {
rootCmds.add(pkCmd);
}
}
}
if (rootCmds.size() == 0) {
return null;
}
}
AbstractClassMetaData rootCmd = rootCmds.get(0);
if (ec != null) {
// Perform a check on the exact object inheritance level with this key (uses SQL query)
if (rootCmds.size() == 1) {
Collection<String> subclasses = getSubClassesForClass(rootCmd.getFullClassName(), true, clr);
if (!rootCmd.isImplementationOfPersistentDefinition()) {
// Not persistent interface implementation so check if any subclasses
if (subclasses == null || subclasses.isEmpty()) {
// so we assume it can't be a supertype
return rootCmd.getFullClassName();
// This commented out code simply restricts if other classes are using the table
/*DatastoreClass primaryTable = getDatastoreClass(rootCmd.getFullClassName(), clr);
String[] managedClassesInTable = primaryTable.getManagedClasses();
if (managedClassesInTable.length == 1 && managedClassesInTable[0].equals(rootCmd.getFullClassName()))
{
if (NucleusLogger.PERSISTENCE.isDebugEnabled())
{
NucleusLogger.PERSISTENCE.debug("Sole candidate for id is " +
rootCmd.getFullClassName() + " and has no subclasses, so returning without checking datastore");
}
return rootCmd.getFullClassName();
}*/
}
}
// Check how many concrete classes we have in this tree, in case only one
int numConcrete = 0;
String concreteClassName = null;
Class rootCls = clr.classForName(rootCmd.getFullClassName());
if (!Modifier.isAbstract(rootCls.getModifiers())) {
concreteClassName = rootCmd.getFullClassName();
numConcrete++;
}
if (subclasses != null) {
for (String subclassName : subclasses) {
Class subcls = clr.classForName(subclassName);
if (!Modifier.isAbstract(subcls.getModifiers())) {
if (concreteClassName == null) {
concreteClassName = subclassName;
}
numConcrete++;
}
}
}
if (numConcrete == 1) {
// Single possible concrete class, so return it
return concreteClassName;
}
// Simple candidate query of this class and subclasses
if (rootCmd.hasDiscriminatorStrategy()) {
// Query using discriminator
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug("Performing query using discriminator on " + rootCmd.getFullClassName() + " and its subclasses to find the class of " + id);
}
return RDBMSStoreHelper.getClassNameForIdUsingDiscriminator(this, ec, id, rootCmd);
}
// Query using UNION
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug("Performing query using UNION on " + rootCmd.getFullClassName() + " and its subclasses to find the class of " + id);
}
return RDBMSStoreHelper.getClassNameForIdUsingUnion(this, ec, id, rootCmds);
}
// Multiple possible roots so use UNION statement
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
StringBuilder str = new StringBuilder();
Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator();
while (rootCmdIter.hasNext()) {
AbstractClassMetaData cmd = rootCmdIter.next();
str.append(cmd.getFullClassName());
if (rootCmdIter.hasNext()) {
str.append(",");
}
}
NucleusLogger.PERSISTENCE.debug("Performing query using UNION on " + str.toString() + " and their subclasses to find the class of " + id);
}
return RDBMSStoreHelper.getClassNameForIdUsingUnion(this, ec, id, rootCmds);
}
// Check not possible so just return the first root
if (rootCmds.size() > 1) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug("Id \"" + id + "\" has been determined to be the id of class " + rootCmd.getFullClassName() + " : this is the first of " + rootCmds.size() + " possible, but unable to determine further");
}
return rootCmd.getFullClassName();
}
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug("Id \"" + id + "\" has been determined to be the id of class " + rootCmd.getFullClassName() + " : unable to determine if actually of a subclass");
}
return rootCmd.getFullClassName();
}
Aggregations